Compare commits

...

1474 Commits

Author SHA1 Message Date
Sun Yimin
8269e67af8
Merge pull request #337 from emmansun/dependabot/github_actions/ossf/scorecard-action-2.4.2
build(deps): bump ossf/scorecard-action from 2.4.1 to 2.4.2
2025-06-23 13:50:42 +08:00
Sun Yimin
a3cc597c7c
Merge pull request #336 from emmansun/dependabot/docker/internal/sm2ec/fiat/coqorg/coq-8.20.1
build(deps): bump coqorg/coq from 8.13.2 to 8.20.1 in /internal/sm2ec/fiat
2025-06-23 13:19:01 +08:00
Sun Yimin
44447bdc35
Merge pull request #335 from emmansun/dependabot/github_actions/actions/upload-artifact-4.6.2
build(deps): bump actions/upload-artifact from 4.6.1 to 4.6.2
2025-06-23 13:10:40 +08:00
Sun Yimin
89bdfdb29c
Merge pull request #334 from emmansun/dependabot/github_actions/github/codeql-action-3.29.0
build(deps): bump github/codeql-action from 2.28.1 to 3.29.0
2025-06-23 11:54:46 +08:00
Sun Yimin
5f56a469ec
Create SECURITY.md 2025-06-23 11:44:43 +08:00
dependabot[bot]
42ec527d4a
build(deps): bump ossf/scorecard-action from 2.4.1 to 2.4.2
Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.4.1 to 2.4.2.
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](f49aabe0b5...05b42c6244)

---
updated-dependencies:
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 03:40:32 +00:00
dependabot[bot]
da48457f60
build(deps): bump coqorg/coq in /internal/sm2ec/fiat
Bumps coqorg/coq from 8.13.2 to 8.20.1.

---
updated-dependencies:
- dependency-name: coqorg/coq
  dependency-version: 8.20.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 03:35:09 +00:00
dependabot[bot]
bf864fbf8b
build(deps): bump actions/upload-artifact from 4.6.1 to 4.6.2
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.1 to 4.6.2.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](4cec3d8aa0...ea165f8d65)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 4.6.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 03:33:29 +00:00
dependabot[bot]
bb693004ef
build(deps): bump github/codeql-action from 2.28.1 to 3.29.0
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.28.1 to 3.29.0.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2.28.1...ce28f5bb42b7a9f2c824e633a3f6ee835bab6858)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 03:33:26 +00:00
Sun Yimin
87cfc1480d
Merge pull request #333 from step-security-bot/chore/GHA-230313-stepsecurity-remediation
[StepSecurity] Apply security best practices
2025-06-23 11:19:50 +08:00
StepSecurity Bot
32564db705
[StepSecurity] Apply security best practices
Signed-off-by: StepSecurity Bot <bot@stepsecurity.io>
2025-06-23 03:13:12 +00:00
Sun Yimin
8125a409f3
Create scorecard.yml 2025-06-23 10:40:02 +08:00
Sun Yimin
967d93a09a
Update codeql-analysis.yml
rename
2025-06-23 10:35:22 +08:00
Sun Yimin
8cfcf01ec3
padding: fix codeql reported security issue 2025-06-23 10:27:45 +08:00
Sun Yimin
59f85b654e
cbcmac: test file uses cbcmac_test package 2025-06-23 08:59:46 +08:00
Sun Yimin
bb64af1a24
all: golint 2025-06-20 10:24:08 +08:00
Sun Yimin
fca59d1a92
all: golint 2025-06-19 16:37:53 +08:00
Sun Yimin
4593cdb30b
all: golint 2025-06-19 13:31:43 +08:00
Sun Yimin
1e53c5f16d
all: lint 2025-06-19 10:38:23 +08:00
Sun Yimin
1a005fa41b
Create licenses.yml 2025-06-18 08:49:51 +08:00
Sun Yimin
b138828e9d
Merge pull request #331 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.39.0
build(deps): bump golang.org/x/crypto from 0.38.0 to 0.39.0
2025-06-10 08:22:30 +08:00
dependabot[bot]
bf6b8b6864
build(deps): bump golang.org/x/crypto from 0.38.0 to 0.39.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.38.0 to 0.39.0.
- [Commits](https://github.com/golang/crypto/compare/v0.38.0...v0.39.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-10 00:03:36 +00:00
Sun Yimin
6a12b6eda9
smx509: switch default policy field to Policies 2025-06-09 13:26:37 +08:00
Sun Yimin
f14097864c
smx509: add new OID type and use it in Certificate #209 2025-06-09 11:19:17 +08:00
Sun Yimin
4abeaf929a
Update doc 2025-06-06 17:24:04 +08:00
Sun Yimin
0606f223cd
Create CITATION.cff 2025-06-04 17:15:54 +08:00
Sun Yimin
0ec4ddf58f
mldsa: bounds check elimination 2025-06-04 11:01:59 +08:00
Sun Yimin
5084ea06e3
mldsa: improve sign/verify performance 2025-06-03 10:38:48 +08:00
Sun Yimin
b218e76328
mldsa: add benchmark for Verify 2025-05-30 15:25:37 +08:00
Sun Yimin
8fc001fb45
mldsa: supplement test cases and comments 2025-05-30 10:06:23 +08:00
Sun Yimin
8f0bd765ca
mldsa: add benchmark test 2025-05-29 08:31:25 +08:00
Sun Yimin
67ac5da71e
mldsa: optimize to read a block once 2025-05-28 16:13:40 +08:00
Sun Yimin
3c24ac0690
slhdsa: go1.24 build 2025-05-27 10:14:54 +08:00
Sun Yimin
6f6631236f
slhdsa: provide handy methods 2025-05-27 10:12:08 +08:00
Sun Yimin
da0d651197
sm2: provide SignMessage method to comply with the [crypto.MessageSigner] interface 2025-05-26 15:10:48 +08:00
Sun Yimin
fe1d170bdc
smx509: use truncated SHA-256 for SubjectKeyId #328 2025-05-26 13:34:12 +08:00
Sun Yimin
7e203652ef
smx509: disallow negative path length #329 2025-05-26 13:18:51 +08:00
Sun Yimin
b2b1a9b56b
sm2: provide low-level encoding functions for keys (alias for NewXXX) 2025-05-26 10:49:25 +08:00
Sun Yimin
08bf93c1b1
slhdsa: align function parameter name 2025-05-22 15:47:56 +08:00
Sun Yimin
c467b22fb9
slhdsa: reduce slice make times and supplement comments 2025-05-22 14:21:24 +08:00
Sun Yimin
44b9419aa7
ci: test coverage for golang 1.24 2025-05-21 13:49:11 +08:00
Sun Yimin
64dbdf27c8
slhdsa: supplement more test cases 2025-05-21 11:41:00 +08:00
Sun Yimin
dd24189d7d
slhdsa: SLH-DSA-SHAKE-128f test cases 2025-05-21 11:20:05 +08:00
Sun Yimin
9f0d175f2c
slhdsa: SLH-DSA initialize 2025-05-21 11:10:44 +08:00
Sun Yimin
b634efb6ad
mldsa: generate mldsa65 mldsa87 based on mldsa44 2025-05-09 10:24:21 +08:00
Sun Yimin
0345946203
mldsa: supplement comments 2025-05-08 10:22:30 +08:00
Sun Yimin
fc7dc9a54a
doc: update README 2025-05-07 15:37:09 +08:00
Sun Yimin
8430ebd36c
mldsa: supports prehash dsa 2025-05-07 15:09:31 +08:00
Sun Yimin
834873f0e8
mldsa: supports prehash dsa 2025-05-07 15:08:36 +08:00
Sun Yimin
dfd4143c65
mldsa: requires golang 1.24+ 2025-05-07 10:09:48 +08:00
Sun Yimin
90522392f1
mldsa: initial implementation NIST FIPS 204 2025-05-07 10:05:13 +08:00
Sun Yimin
07bf6835b7
Merge pull request #325 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.38.0
build(deps): bump golang.org/x/crypto from 0.37.0 to 0.38.0
2025-05-06 08:17:00 +08:00
dependabot[bot]
32d5c4c0c5
build(deps): bump golang.org/x/crypto from 0.37.0 to 0.38.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.37.0 to 0.38.0.
- [Commits](https://github.com/golang/crypto/compare/v0.37.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-06 00:09:53 +00:00
Sun Yimin
7b75b6b26b
update disclaimer 2025-04-18 08:50:39 +08:00
Sun Yimin
5aacbc2011
Merge pull request #324 from hrimfaxi/main
sm9: Prevent PublicKey() returning nil after unmarshaling master priavate key
2025-04-15 17:31:55 +08:00
YuanHongYe
fe532e12b4 sm9: Prevent PublicKey() returning nil after unmarshaling master private key
During unmarshaling of SignMasterPrivateKey and EncryptMasterPrivateKey,
now generate the corresponding public key.
This ensures that PublicKey() does not return nil.

Test cases included to validate the changes.

Signed-off-by: YuanHongYe <yuanhongye@chinatelecom.cn>
2025-04-15 17:01:27 +08:00
Sun Yimin
1dc82305e4
Merge pull request #323 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.37.0
build(deps): bump golang.org/x/crypto from 0.36.0 to 0.37.0
2025-04-08 09:28:54 +08:00
dependabot[bot]
ed256a9ea3
build(deps): bump golang.org/x/crypto from 0.36.0 to 0.37.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.36.0 to 0.37.0.
- [Commits](https://github.com/golang/crypto/compare/v0.36.0...v0.37.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-08 00:52:59 +00:00
Sun Yimin
d8c6788e8f
sm2, sm2ec: remove useless codes since go 1.19 2025-04-07 13:10:09 +08:00
Sun Yimin
0ef30b3ab5
internal/zuc: supplement comments 2025-04-03 10:40:06 +08:00
Sun Yimin
d3eece5560
cfca: fix test cases #322 2025-04-01 17:06:47 +08:00
Sun Yimin
0af92d8e48
smx509: CFCA CSR supports RSA keys #322 2025-04-01 17:02:13 +08:00
Sun Yimin
bf644fbb4e
docs/zuc: add seekable stream part 2025-03-28 17:19:19 +08:00
Sun Yimin
359b46453b
internal/zuc,zuc: eea seakable stream support zuc states cache per bucket #321 2025-03-28 16:53:29 +08:00
Sun Yimin
b8d52dd11d
internal/sm9/bn256: make gfP.Unmarshal constant time 2025-03-26 16:37:04 +08:00
Sun Yimin
9ea8293d10
internal/sm2ec/fiat: fix error message 2025-03-26 15:20:30 +08:00
Sun Yimin
e8a847e005
internal/sm9/bn256: remove useless code 2025-03-26 09:49:30 +08:00
Sun Yimin
a7c4473a48
internal/sm9/bn256: reduce big.Int usage 2025-03-26 09:30:39 +08:00
Sun Yimin
11d0438cc4
internal/sm9: reduce usage of big.Int 2025-03-25 17:19:10 +08:00
Sun Yimin
88df15c64c
sm9: implement crypto.Singer crypto.Decrypter interface 2025-03-25 14:58:16 +08:00
Sun Yimin
3eea15b3b8
internal/sm9,sm9: refactor all keys 2025-03-25 11:10:53 +08:00
Sun Yimin
dd69d32930
drbg: replace with for range 2025-03-25 08:49:56 +08:00
Sun Yimin
a84fec09af
internal/cpu: move to internal/deps/cpu #310 2025-03-21 10:04:35 +08:00
Sun Yimin
c43e0488a6
cbcmac: fix typo 2025-03-21 08:38:59 +08:00
Sun Yimin
a4affe6006
cbcmac,padding: supplement/update comments 2025-03-20 16:34:19 +08:00
Sun Yimin
3cc92436ee
padding: fix "Size computation for allocation may overflow" 2025-03-19 11:16:26 +08:00
Sun Yimin
93c965f3c1
cipher: move xts detail implementation to internal #320 2025-03-19 10:21:52 +08:00
Sun Yimin
d8eb166dfc
cbcmac: enable provided padding for EMAC/ANSI Retail MAC/MAC-DES/LMAC #319 2025-03-19 10:10:00 +08:00
Sun Yimin
2d3329a2ea
padding: missing PaddingFunc #319 2025-03-18 11:44:45 +08:00
Sun Yimin
f41a5c69e7
cbcmac: CBCMAC enable provided padding method #319 2025-03-18 11:41:04 +08:00
Sun Yimin
cf027254dc
update README #319 2025-03-18 11:27:28 +08:00
Sun Yimin
069babe703
padding: implement ISO IEC9797-1 padding method 3 #319 2025-03-18 11:21:48 +08:00
Sun Yimin
5734e67634
internal/cpu,internal/sm9: refactor and fix 2025-03-17 17:18:58 +08:00
Sun Yimin
82ccb95527
sm9,internal/sm9: update comments #314 2025-03-14 15:26:34 +08:00
Sun Yimin
e79aab4935
smx509: better handling of weird encodings #316 2025-03-14 08:44:52 +08:00
Sun Yimin
c32a9849f8
sm9: refactoring #314 2025-03-13 16:50:28 +08:00
Sun Yimin
7ec46d700d
internal/subtle: remove xor related codes #315 2025-03-13 15:20:05 +08:00
Sun Yimin
7a5253bfb5
change to use go's own XORBytes function #315 2025-03-13 15:15:46 +08:00
Sun Yimin
d6f18a2cbf
fix CI 2025-03-13 14:44:56 +08:00
Sun Yimin
bdb169b06b
sm9: refactoring, do not expose bn256 types to caller #314 2025-03-13 14:14:45 +08:00
Sun Yimin
43ffd49e2f
sm9: refactoring, do not expose bn256 types to caller #314 2025-03-13 13:46:14 +08:00
Sun Yimin
e9692d23ab
zuc: remove useless constants 2025-03-11 16:26:41 +08:00
Sun Yimin
21f96e536b
internal/zuc: fix build error 2025-03-11 16:13:59 +08:00
Sun Yimin
a49eecd572
zuc: move implementation detail to internal 2025-03-11 16:11:18 +08:00
Sun Yimin
537c80a28b
sm3: move implementation detail to internal 2025-03-11 14:02:47 +08:00
Sun Yimin
5edcb0f966
sm4: move implementation detail to internal 2025-03-11 11:43:49 +08:00
Sun Yimin
65a69ad83c
internal/bigmod: explicitly clear expanded limbs on reset #313 2025-03-11 08:58:16 +08:00
Sun Yimin
71b196a5ac
Merge pull request #312 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.36.0
build(deps): bump golang.org/x/crypto from 0.35.0 to 0.36.0
2025-03-11 08:20:58 +08:00
dependabot[bot]
500cb8a418
build(deps): bump golang.org/x/crypto from 0.35.0 to 0.36.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.35.0 to 0.36.0.
- [Commits](https://github.com/golang/crypto/compare/v0.35.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 23:41:37 +00:00
Sun Yimin
762cbbf0c6
ci: check macOs 2025-03-05 15:09:15 +08:00
Sun Yimin
9d6f8087f9
internal/cpu: correct import #310 2025-03-05 15:03:21 +08:00
Sun Yimin
a6d8014ac9
internal/cpu: missing one #310 2025-03-05 14:58:28 +08:00
Sun Yimin
d7a6169fbf
internal/cpu: import codes from golang.org/x/sys/cpu #310 2025-03-05 14:54:51 +08:00
Sun Yimin
67f187b1d3
sm4: define & use type KeySizeError 2025-03-05 10:56:13 +08:00
Sun Yimin
759bb4c0b9
internal/sm2ec: make SetBytes constant time, use latest golang features #309 2025-03-04 11:30:20 +08:00
Sun Yimin
5ade794e6b
internal/sm2ec: make SetBytes constant time #309 2025-03-04 08:59:51 +08:00
Sun Yimin
89962cf1e3
smx509: avoid crypto/rand.Int to generate serial number #308 2025-03-04 08:48:18 +08:00
Sun Yimin
d433e416fa
ci: enable code coverage 2025-02-27 13:08:09 +08:00
Sun Yimin
2c0f5f68fc
smx509: add support for PKCS8/PKIX X25519 key encodings #210 2025-02-27 11:44:53 +08:00
Sun Yimin
3d4dd002a4
smx509: add new CRL parser, deprecate old one #40 2025-02-27 10:22:19 +08:00
Sun Yimin
9ba88a32a4
smx509: use bytes.Clone 2025-02-27 08:16:07 +08:00
Sun Yimin
0bb54adc1e
cipher: use new functions 2025-02-26 11:46:48 +08:00
Sun Yimin
a98b806453
padding: use new function clear() 2025-02-26 11:41:47 +08:00
Sun Yimin
51a003b022
sm3: remove duplicated code 2025-02-26 11:16:47 +08:00
Sun Yimin
dc1c5806c9
internal/bigmod: use clear() 2025-02-26 10:50:35 +08:00
Sun Yimin
869be23867
sm4: remove unused package 2025-02-26 10:26:29 +08:00
Sun Yimin
8a25134c82
sm4: fallback ctr change 2025-02-26 10:24:46 +08:00
Sun Yimin
27e7ceacbc
sm4: use new functions: clear(), bytes.Clone() 2025-02-26 10:19:56 +08:00
Sun Yimin
ec8580b01f
sm2: fix go1.24 test issue 2025-02-26 09:46:03 +08:00
Sun Yimin
2192b702b0
upgrade github action to 1.23+ 2025-02-26 08:50:00 +08:00
Sun Yimin
d03a8fba3f
upgrade to go 1.23 2025-02-26 08:46:40 +08:00
Sun Yimin
33c609242c
internal/cpuid: use var block 2025-02-26 08:25:58 +08:00
Sun Yimin
d2dd4de947
doc: add smart questions link 2025-02-18 08:49:36 +08:00
Sun Yimin
1aed89febd
subtle: combine xor_<goarch>.go files #304 2025-02-17 08:32:20 +08:00
Sun Yimin
a248fea7f9
Merge pull request #302 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.33.0
build(deps): bump golang.org/x/crypto from 0.32.0 to 0.33.0
2025-02-11 07:34:43 +08:00
dependabot[bot]
53465ae10a
build(deps): bump golang.org/x/crypto from 0.32.0 to 0.33.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.32.0 to 0.33.0.
- [Commits](https://github.com/golang/crypto/compare/v0.32.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-10 23:30:00 +00:00
Sun Yimin
ea592fe3d0
cfca: fix typo 2025-01-23 16:35:32 +08:00
Sun Yimin
9e57bb91b2
cfca: add examples 2025-01-23 11:28:54 +08:00
Sun Yimin
ee55d370f8
improve test coverage and remove deprecated methods 2025-01-22 10:28:01 +08:00
Sun Yimin
4c88efbaee
sm2: provide a specific hash.Hash implementation #297 2025-01-20 17:36:46 +08:00
Sun Yimin
80a264c995
sm2: update document 2025-01-17 13:54:16 +08:00
Sun Yimin
50a5e49d38
smx509: properly check for IPv6 hosts in URIs #296 2025-01-17 08:30:27 +08:00
Sun Yimin
cb51b3657a
pkcs7: sync with upstream 2025-01-16 16:04:45 +08:00
Sun Yimin
cf6e203d06
pkcs7: update comments and document 2025-01-16 10:59:30 +08:00
Sun Yimin
057ddb5bcb
pkcs7: fix error message 2025-01-15 17:18:37 +08:00
Sun Yimin
94e533ca15
pkcs7: fix typo #294 2025-01-15 08:50:09 +08:00
Sun Yimin
818e14ee32
pkcs7: fix verify signing time check issue #294 2025-01-14 17:10:00 +08:00
Sun Yimin
8331b37e37
pkcs7: deleted a line by mistake #294 2025-01-14 16:52:15 +08:00
Sun Yimin
bef7f5421e
pkcs7: sign precomputed digest #294 2025-01-14 16:41:03 +08:00
Sun Yimin
5a0ff81dc3
Merge pull request #293 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.32.0
build(deps): bump golang.org/x/crypto from 0.31.0 to 0.32.0
2025-01-07 07:53:00 +08:00
dependabot[bot]
b865b59a95
build(deps): bump golang.org/x/crypto from 0.31.0 to 0.32.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.31.0 to 0.32.0.
- [Commits](https://github.com/golang/crypto/compare/v0.31.0...v0.32.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-06 23:48:52 +00:00
Sun Yimin
0a961f152c
Merge pull request #292 from emmansun/dependabot/go_modules/golang.org/x/sys-0.29.0
build(deps): bump golang.org/x/sys from 0.28.0 to 0.29.0
2025-01-07 07:47:51 +08:00
dependabot[bot]
3544c09801
build(deps): bump golang.org/x/sys from 0.28.0 to 0.29.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.28.0 to 0.29.0.
- [Commits](https://github.com/golang/sys/compare/v0.28.0...v0.29.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-06 23:43:07 +00:00
Sun Yimin
e5652b6638
smx509: add wasip1 support #290 2024-12-27 08:07:33 +08:00
Sun Yimin
309e920050
doc: update sm2.md 2024-12-20 17:57:35 +08:00
Sun Yimin
805fa40c97
pkcs7: code review and refactor 2024-12-20 08:34:32 +08:00
Sun Yimin
d199697b20
pkcs7: remove deprecated method SignWithSM2 2024-12-19 15:42:19 +08:00
Sun Yimin
6b18205bba
sm2: fix test cases 2024-12-19 08:28:00 +08:00
Sun Yimin
89317b8f0b
sm2: code review and refactor 2024-12-19 08:17:21 +08:00
Sun Yimin
a71e806a2d
sm9: code review 2024-12-17 18:06:15 +08:00
Sun Yimin
a53c8b97f8
Merge pull request #289 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.31.0
build(deps): bump golang.org/x/crypto from 0.30.0 to 0.31.0
2024-12-17 07:28:08 +08:00
dependabot[bot]
4fd9003243
build(deps): bump golang.org/x/crypto from 0.30.0 to 0.31.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.30.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.30.0...v0.31.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 23:17:20 +00:00
Sun Yimin
0d3a2d2d18
cfca: pkcs12 sm2, supplement test data 2024-12-16 12:54:36 +08:00
Sun Yimin
008b209765
cfca: pkcs7 test, avoid random failure 2024-12-13 18:16:08 +08:00
Sun Yimin
ab670f8ced
cfca: pkcs7 test, avoid random failure 2024-12-13 18:14:06 +08:00
Sun Yimin
8e02380f47
update README 2024-12-13 18:07:41 +08:00
Sun Yimin
ac38d8f6aa
cfca: test trustAsia generated csr 2024-12-13 15:37:27 +08:00
Sun Yimin
d2e96cff57
cfca: update test error message 2024-12-13 08:20:48 +08:00
Sun Yimin
1bbcc232db
cfca: test sadk generated csr #286 2024-12-12 17:55:57 +08:00
Sun Yimin
cdf1805d4f
smx509: cfca csr add comments and align tmp publickey encoding 2024-12-12 17:34:12 +08:00
Sun Yimin
6a98350f2e
cfca: extract encrypt/decrypt functions with SM4CBC and SM3 KDF 2024-12-11 17:51:31 +08:00
Sun Yimin
65532624e8
cfca pkcs10 rename and improve test coverage #286 2024-12-11 10:06:27 +08:00
Sun Yimin
3371b7c65c
cfca csr with tmp publickey and parse returned encryption key #286 2024-12-11 08:36:55 +08:00
Sun Yimin
c6881ae849
update cfca document 2024-12-10 10:29:22 +08:00
Sun Yimin
df3db923c6
support cfca certificate request #286 2024-12-10 10:13:51 +08:00
Sun Yimin
1d894ef955
fix test case 2024-12-10 09:24:05 +08:00
Sun Yimin
a3161b7581
support cfca certificate request #286 2024-12-10 09:01:21 +08:00
Sun Yimin
01b0570c3a
support cfca certificate request #286 2024-12-10 08:57:35 +08:00
Sun Yimin
717a0feea6
Merge pull request #288 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.30.0
build(deps): bump golang.org/x/crypto from 0.29.0 to 0.30.0
2024-12-10 07:20:21 +08:00
dependabot[bot]
39bb9469b1
build(deps): bump golang.org/x/crypto from 0.29.0 to 0.30.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.29.0 to 0.30.0.
- [Commits](https://github.com/golang/crypto/compare/v0.29.0...v0.30.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-09 23:13:22 +00:00
Sun Yimin
5ada783793
Merge pull request #287 from emmansun/dependabot/go_modules/golang.org/x/sys-0.28.0
build(deps): bump golang.org/x/sys from 0.27.0 to 0.28.0
2024-12-10 07:12:16 +08:00
dependabot[bot]
4c5dc14a6b
build(deps): bump golang.org/x/sys from 0.27.0 to 0.28.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.27.0 to 0.28.0.
- [Commits](https://github.com/golang/sys/compare/v0.27.0...v0.28.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-09 23:07:16 +00:00
Sun Yimin
1d24c4640d
pkcs7: fallback change 2024-12-09 20:05:39 +08:00
Sun Yimin
531388ce5e
pkcs7: fallback change 2024-12-09 19:59:41 +08:00
Sun Yimin
1cf8782870
pkcs7: fallback change 2024-12-09 19:54:01 +08:00
Sun Yimin
0d1fe8c95c
cfca: add pkcs7 signed data facade 2024-12-09 18:00:40 +08:00
Sun Yimin
90fa2233a8
zuc: eea seek benchmark test and refactor 2024-12-06 16:36:24 +08:00
Sun Yimin
865159d86a
internal/bigmod: add more //go:norace annotations and refactoring 2024-12-06 08:54:47 +08:00
Sun Yimin
0d56114869
zuc: eea XORKeyStreamAt avoid useless calculation 2024-12-05 18:13:23 +08:00
Sun Yimin
9bfea6d73d
zuc: eea XORKeyStreamAt fix issue 2024-12-05 17:59:02 +08:00
Sun Yimin
f644a483e3
cbcmac: implement hash interface for cmac 2024-12-05 17:39:45 +08:00
Sun Yimin
379396b688
zuc: eea XORKeyStreamAt fix issue 2024-12-05 17:32:24 +08:00
Sun Yimin
fcd1aa22d2
internal/bigmod: disable race detector on tight loops #285 2024-12-05 08:33:11 +08:00
Sun Yimin
14087e2665
zuc: refactor the eea test case issue #284 2024-12-05 08:14:21 +08:00
Sun Yimin
ddb5b69b53
fix #284 2024-12-04 18:54:19 +08:00
Sun Yimin
d009f7ebef
internal/bigmod: sync bigmod change between 30/Nov 2024 to 3/Dec 2024 #282 2024-12-03 17:57:27 +08:00
Sun Yimin
a599819ef8
cfca: provide cfca envelope message facades #283 2024-12-03 17:53:25 +08:00
Sun Yimin
0e154ad9cb
cbc-mac supplement test cases and document #281 2024-12-03 17:48:25 +08:00
Sun Yimin
e6a8b84935
cbcmac: supplement test cases #281 2024-12-03 08:20:59 +08:00
Sun Yimin
f419e78566
Support CBC-MAC and its variants #281 2024-12-02 17:57:51 +08:00
Sun Yimin
30077cd1d6
ci: test purego ignore 1.23 first, there's one bug in golang 2024-11-29 17:46:40 +08:00
Sun Yimin
9582d8e524
ci: test golang 1.23 2024-11-29 17:09:24 +08:00
Sun Yimin
d90f8d62e1
zuc: seekable stream, refactor the test case #277 2024-11-29 16:07:31 +08:00
Sun Yimin
895c0db489
zuc: seekable stream refactoring and fix bug #277 2024-11-29 15:19:19 +08:00
Sun Yimin
da9f9c1748
zuc: seakable stream #277 2024-11-29 11:44:59 +08:00
Sun Yimin
f458fe69cf
sm2/sm2ec: move sm2 related to sm2ec.go 2024-11-28 14:55:32 +08:00
Sun Yimin
8264b5f42c
internal/bigmod: add support for even moduli #280 2024-11-27 08:59:46 +08:00
Sun Yimin
e08954dd45
internal/bigmod: add support for even moduli #280 2024-11-27 08:56:11 +08:00
Sun Yimin
4df708a76b
internal/bigmod: add support for even moduli #280 2024-11-27 08:52:03 +08:00
Sun Yimin
dec688f7cc
ecdh: update comments 2024-11-26 17:48:32 +08:00
Sun Yimin
9fd122e614
x509: generate serial number for nil template SerialNumber #279 2024-11-25 08:41:30 +08:00
Sun Yimin
e2c430a0ff
zuc: add comments 2024-11-22 08:33:24 +08:00
Sun Yimin
5c2a22ec2a
pkcs7: update comments #276 2024-11-21 17:53:35 +08:00
Sun Yimin
bc0e11e9b1
pkcs7: provide session interface #276 2024-11-21 17:35:23 +08:00
Sun Yimin
8c6297d00f
internal/sm2ec: improve purego implementation's performance #274 2024-11-21 14:42:40 +08:00
Sun Yimin
bf14e70c4b
internal/byteorder: new package #275 2024-11-21 14:32:32 +08:00
Sun Yimin
4f7504c6b9
internal/bigmod: optimize SetOverflowedBytes #273 2024-11-20 18:15:32 +08:00
Sun Yimin
9624b43515
internal/bigmod: drop math/big dependency #273 2024-11-20 18:06:29 +08:00
Sun Yimin
cd60dad621
internal/subtle: document and test XORBytes overlap rules #272 2024-11-20 14:21:16 +08:00
Sun Yimin
6e742e69ef
pkcs7: change EncryptedContent to implicit #270 2024-11-20 09:55:30 +08:00
Sun Yimin
0e616425aa
update CFCA document #270 2024-11-20 08:32:02 +08:00
Sun Yimin
0205d1ae47
pkcs7: improve compatibility with CFCA #270 2024-11-20 08:22:43 +08:00
Sun Yimin
c9f55b045f
smx509: ParseCertificatePEM validate type 2024-11-19 10:55:41 +08:00
Sun Yimin
1aefd6f1f6
update doc 2024-11-18 17:23:59 +08:00
Sun Yimin
34a6ad2fc0
sm3: arm64 sm3ni change slice to array 2024-11-14 08:40:53 +08:00
Sun Yimin
dee08a50f3
sm3: ppc64x predefine constants for ROTL 2024-11-14 08:32:31 +08:00
Sun Yimin
8f45f4efcb
sm3: ppc64x change T handling method #267 2024-11-13 17:41:09 +08:00
Sun Yimin
d263ac5889
sm3: ppc64x fix constant issue 2024-11-12 17:49:58 +08:00
Sun Yimin
51c8f4905d
sm3: s390x transpose matrix #266 2024-11-12 17:40:33 +08:00
Sun Yimin
8d25450d3c
sm3: try s390x transpose matrix optimization 2024-11-12 10:34:52 +08:00
Sun Yimin
b22aeea329
sm3: ppc64x transpose matrix #265 2024-11-12 08:56:17 +08:00
Sun Yimin
27ba0a040c
Merge pull request #264 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.29.0
build(deps): bump golang.org/x/crypto from 0.28.0 to 0.29.0
2024-11-12 07:54:33 +08:00
dependabot[bot]
01ff26e346
build(deps): bump golang.org/x/crypto from 0.28.0 to 0.29.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.28.0 to 0.29.0.
- [Commits](https://github.com/golang/crypto/compare/v0.28.0...v0.29.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-11 23:42:17 +00:00
Sun Yimin
1d6886f069
zuc: fix typo 2024-11-11 18:03:41 +08:00
Sun Yimin
58ad15fde8
zuc: refactoring 2024-11-11 17:53:57 +08:00
Sun Yimin
1f209d2317
sm4:arm64 fix sm4ni compile issue 2024-11-11 17:47:57 +08:00
Sun Yimin
e6d2deb51e
sm4: arm64 fix typo 2024-11-11 17:43:32 +08:00
Sun Yimin
aa82b5836b
sm4: use package level instead of local for shared variables 2024-11-11 17:40:41 +08:00
Sun Yimin
b721bed0cc
zuc: minor optimization 2024-11-08 11:03:43 +08:00
Sun Yimin
a33c2ae118
zuc: eia256 ppc64x use VPERXOR for bit reverse #262 2024-11-08 09:25:02 +08:00
Sun Yimin
9057b79253
zuc: eia VPERMXOR for bit reverse 2024-11-08 09:00:08 +08:00
Sun Yimin
7c50a612cc
zuc: ppc64x uses XPERMXOR for zuc sbox 2024-11-08 08:48:57 +08:00
Sun Yimin
99972206e5
sm4: ppc64x uses VPERMXOR to implement Affine Transform 2024-11-08 08:24:35 +08:00
Sun Yimin
64df0fca61
sm4: ppc64x try VPERMXOR 2 2024-11-08 08:11:32 +08:00
Sun Yimin
4e5e3d0128
sm4: ppc64x try VPERMXOR 2024-11-08 08:09:45 +08:00
Sun Yimin
f7263ee31e
ppc64x: rollback again 2024-11-07 18:08:02 +08:00
Sun Yimin
08617245e0
ppc64x: try VPERMXOR last 2024-11-07 18:04:59 +08:00
Sun Yimin
965f0d1119
ppc64x: rollback first 2024-11-07 17:57:26 +08:00
Sun Yimin
756ec1e6df
ppc64x: try VPERMXOR 2 2024-11-07 17:54:30 +08:00
Sun Yimin
189b2d990e
ppc64x: try VPERMXOR 2024-11-07 17:39:31 +08:00
Sun Yimin
16219eef8a
ppc64x: sm4/zuc reduce VAND 2024-11-07 17:19:53 +08:00
Sun Yimin
1924799006
arm64: sm4/zuc reduce VAND 2024-11-07 17:03:56 +08:00
Sun Yimin
6e84600b31
sm4: ppc64x fix address #261 2024-11-06 18:05:37 +08:00
Sun Yimin
a556119339
sm4: ppc64x fix address #261 2024-11-06 17:58:58 +08:00
Sun Yimin
30c9483382
sm4: ppc64x remove useless definition #261 2024-11-06 17:44:44 +08:00
Sun Yimin
43b35e7aa0
sm4: ppc64x transpose matrix #261 2024-11-06 17:31:19 +08:00
Sun Yimin
ef06ce03ac
doc: update cfca 2024-11-04 08:58:13 +08:00
Sun Yimin
8e2f6c13de
pkcs7: align pkix.AlgorithmIdentifier Null Parameters with others 2024-10-30 08:57:45 +08:00
Sun Yimin
559da498c9
sm4: gcm purego optimize NewGCM 2024-10-30 08:31:12 +08:00
Sun Yimin
ac075d803c
sm4:gcminit sm4-ni fix sm4e instruction 2024-10-29 22:37:54 +08:00
Sun Yimin
ea4a07c60c
sm4: gcminit sm4–ni fix instruction error 2024-10-29 22:01:22 +08:00
Sun Yimin
b63aae6ee1
sm4: fix gcm init sm4-ni issue 2024-10-29 21:56:30 +08:00
Sun Yimin
3ea98a3281
zuc: arm64 fix package level variable definition 2024-10-22 08:34:19 +08:00
Sun Yimin
60c8f4550d
zuc: arm64 fix copy paste issue 2024-10-22 08:20:43 +08:00
Sun Yimin
9ef8077107
zuc: eia arm64 redefine constants 2024-10-22 08:14:56 +08:00
Sun Yimin
556e93e69f
sm4: arm64 sm4key export optimization 2024-10-21 15:55:40 +08:00
Sun Yimin
6f3271d354
Merge pull request #257 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.28.0
build(deps): bump golang.org/x/crypto from 0.27.0 to 0.28.0
2024-10-08 08:15:40 +08:00
dependabot[bot]
81a74b0c95
build(deps): bump golang.org/x/crypto from 0.27.0 to 0.28.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.27.0 to 0.28.0.
- [Commits](https://github.com/golang/crypto/compare/v0.27.0...v0.28.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-07 23:47:10 +00:00
Sun Yimin
19bd29a207
pkcs7: SignWithoutAttr supports skip certificates #254 2024-10-07 15:02:49 +08:00
Sun Yimin
c8a803369a
update README 2024-10-06 11:44:26 +08:00
Sun Yimin
fcdfc40cf0
sm9/bn256: ppc64x conditional move fix #256 2024-10-06 11:39:19 +08:00
Sun Yimin
9740519bb3
sm9/bn256: ppc64x test move #256 2024-10-06 11:29:58 +08:00
Sun Yimin
42e1018e36
sm9/bn256: ppc64x test move 2024-10-06 11:25:45 +08:00
Sun Yimin
2455a45871
sm9/bn256: ppc64x value copy/conditional move #256 2024-10-06 10:45:20 +08:00
Sun Yimin
74d1bb82e4
sm9/bn256: ppc64x gfp #256 2024-10-06 09:45:50 +08:00
Sun Yimin
ed4eafdc3e
sm9/bn256: ppc64x gfp sqr 2024-10-05 17:17:51 +08:00
Sun Yimin
9477b78fec
sm9/bn256: ppc64x gfp mul 2024-10-05 16:33:01 +08:00
Sun Yimin
fca2c5e936
sm9/bn256: ppc64x test sub self 2024-10-05 14:02:28 +08:00
Sun Yimin
9a3d21eaec
sm9/bn256: gfp ppc64x fix neg 2024-10-05 13:42:54 +08:00
Sun Yimin
23b4d7ef72
sm9/bn256: gfp ppc64x add/sub/neg fix 3 2024-10-05 13:15:59 +08:00
Sun Yimin
354560331f
sm9/bn256: gfp add/sub fix 2 2024-10-05 12:39:20 +08:00
Sun Yimin
81c4bd077c
sm9/bn256: gfp ppc64x add/sub fix 2024-10-05 12:28:59 +08:00
Sun Yimin
da7a9d6ef0
fix compile error 2024-10-05 12:04:58 +08:00
Sun Yimin
60799ec2e9
fix compile error 2024-10-05 12:00:02 +08:00
Sun Yimin
d2262c4d61
fix compile error 2024-10-05 11:56:00 +08:00
Sun Yimin
d1eb7b386b
rename functions 2024-10-05 11:53:44 +08:00
Sun Yimin
0ef82b1be5
sm9/bn256: gfp ppc64x add/sub 2024-10-05 11:51:31 +08:00
Sun Yimin
94372eac9d
zuc: eea ppc4x fix fast return issue #255 2024-10-03 17:11:15 +08:00
Sun Yimin
b7d66dbbc7
zuc: eea ppc64x fix compile issue #255 2024-10-03 16:47:45 +08:00
Sun Yimin
f11b2781e7
zuc: ppc64x, fix compile issue #255 2024-10-03 16:38:39 +08:00
Sun Yimin
0760bce984
zuc: eea ppc64x, fix 1 #255 2024-10-03 16:26:28 +08:00
Sun Yimin
12dcfbac1c
zuc: eea ppc64x, fix compile issue #255 2024-10-03 15:52:24 +08:00
Sun Yimin
9dc7633a48
zuc: ppc64x core/eea #255 2024-10-03 15:45:17 +08:00
Sun Yimin
d9e452d386
zuc: ppc64x, R1/R2 2024-10-03 14:44:27 +08:00
Sun Yimin
c55ca96151
zuc: ppc64x, use correct M1 M2 2024-10-03 14:40:50 +08:00
Sun Yimin
bfaa1f899d
zuc: ppc64x, check f32 2024-10-03 14:10:43 +08:00
Sun Yimin
b291c58f1f
zuc: ppc64x, check S1 2024-10-03 13:57:26 +08:00
Sun Yimin
a193c5dec0
zuc: ppc64x, check r1 r2 2024-10-03 13:45:17 +08:00
Sun Yimin
c8a9036abf
zuc: ppc64x core fix 3 2024-10-03 13:37:20 +08:00
Sun Yimin
3196df5637
zuc: ppc64x, fix f32 2 2024-10-03 13:15:19 +08:00
Sun Yimin
d7e7df7d1b
zuc: ppc64x fix f32 1 2024-10-03 13:03:46 +08:00
Sun Yimin
d8dbbf4a58
zuc: ppc64x, fix constants error 2024-10-03 12:46:02 +08:00
Sun Yimin
652f4d0393
zuc: ppc64x fix compile error 2 2024-10-03 12:37:39 +08:00
Sun Yimin
42d60f042d
zuc: ppc64x, fix compile error 2024-10-03 12:26:58 +08:00
Sun Yimin
0904554637
zuc: ppc64x genKeywordAsm 1 2024-10-03 12:22:20 +08:00
Sun Yimin
7cfcabad54
zuc: arm64 optimization 2024-10-01 22:33:25 +08:00
Sun Yimin
e1c457c1f0
internal/cryptotest: fix typos in AEAD test comments 2024-10-01 11:37:10 +08:00
Sun Yimin
68056a6730
update document #253 2024-10-01 10:33:51 +08:00
Sun Yimin
5c71299f5e
zuc: eia256 ppc64x tag size 8 fix 2 #253 2024-10-01 10:13:02 +08:00
Sun Yimin
3f1ae9e725
zuc: eia256 ppc64x typo #253 2024-10-01 09:54:59 +08:00
Sun Yimin
7750225963
zuc: eia256 ppc64x fix tag size 8 #253 2024-10-01 09:52:31 +08:00
Sun Yimin
282e061b3b
zuc: eia256 ppc64x fix 2024-10-01 09:41:21 +08:00
Sun Yimin
25edd4d12d
zuc: eia256 ppc64x #253 2024-10-01 09:31:51 +08:00
Sun Yimin
8af20b9de6
Update eia_asm_ppc64x.s 2024-09-30 21:08:35 +08:00
Sun Yimin
3d3d895eb7
Update eia_asm_ppc64x.s 2024-09-30 19:50:39 +08:00
Sun Yimin
c48a0a7be5
Update eia_asm_ppc64x.s 2024-09-30 18:29:13 +08:00
Sun Yimin
0adad613a8
zuc: eia128 ppc64x fix bug 2024-09-30 17:35:08 +08:00
Sun Yimin
50f5d29e49
zuc: eia, ppc64x optimization #253 2024-09-30 17:27:26 +08:00
Sun Yimin
c33880ebe3
ci: ppc64le zuc 2024-09-30 11:37:31 +08:00
Sun Yimin
2f3ec65c88
zuc: eia128 ppc64x 2024-09-30 11:36:06 +08:00
Sun Yimin
ff59b79d60
pkcs7: support GetRecipients #252 2024-09-30 08:26:42 +08:00
Sun Yimin
3968b9d8b5
fix test case 2024-09-26 17:48:47 +08:00
Sun Yimin
a88c13298b
ppc64x, verify VPMSUMD 2024-09-26 17:45:15 +08:00
Sun Yimin
425e65c16d
ppc64x, check VPMSUMD detail 2024-09-26 17:31:15 +08:00
Sun Yimin
018790709a
sm3: ppc64x, confirm usage 2024-09-25 13:47:04 +08:00
Sun Yimin
e535826291
sm3: ppc64x, confirm understanding 2024-09-25 13:43:44 +08:00
Sun Yimin
25e0700f81
xts/gcm: arm64 use VSRI/VSLI 2024-09-24 08:32:42 +08:00
Sun Yimin
f47051ed86
cipher: xts reduce duplicated code 2024-09-24 08:09:57 +08:00
Sun Yimin
5c6c1890ae
cipher: xts ppc64x fix 1 2024-09-23 17:56:13 +08:00
Sun Yimin
4808935f60
cipher: xts ppc64x 2024-09-23 17:50:16 +08:00
Sun Yimin
c305795f55
sm4: ppc64x, use VSBOX #249 2024-09-23 14:10:37 +08:00
Sun Yimin
18b117f4bb
cipher: xts s390x fix bug 2024-09-21 11:42:13 +08:00
Sun Yimin
8963864ff5
cipher: xts s390x instruction issue 2024-09-21 11:22:08 +08:00
Sun Yimin
0178d7489c
cipher: xts s390x 2024-09-21 11:18:54 +08:00
Sun Yimin
022e85231e
#248, rollback changes 2024-09-20 18:02:11 +08:00
Sun Yimin
5c38bb3add
#248, use kimd directly 2024-09-20 17:55:39 +08:00
Sun Yimin
925472fed4
cipher: s390x, gcm mode ghash #248 2024-09-20 17:39:23 +08:00
Sun Yimin
761746de78
sm4: amd64, a bit change for single block 2024-09-19 17:52:12 +08:00
Sun Yimin
6eb5efd898
sm4: expandkey align with single block encryption 2024-09-18 08:56:45 +08:00
Sun Yimin
acdc78cff5
update README 2024-09-13 15:16:57 +08:00
Sun Yimin
f2e122f90d
sm4: ppc64x, gcm fix bug #249 2024-09-13 15:06:08 +08:00
Sun Yimin
7e966a56de
sm4: ppc64x, gcm fix package usage #249 2024-09-13 14:35:43 +08:00
Sun Yimin
e8d1100481
sm4: ppc64x, gcm with EncryptBlocks 2024-09-13 14:32:04 +08:00
Sun Yimin
78d55a69bc
sm4: ppc64x, gcm step 1 (without AESNI) #249 2024-09-13 13:31:54 +08:00
Sun Yimin
37493fe3df
sm4: arm64 cbc, fix register usage issue 2024-09-13 11:23:31 +08:00
Sun Yimin
e5af209d83
cipher: fix copy/paste issue 2024-09-13 11:13:34 +08:00
Sun Yimin
20f0807451
sm4: arm64 cbc decrypt, reduce memory load 2024-09-13 11:06:41 +08:00
Sun Yimin
fd9030c92d
sm4: ppc64x, cbc fix src and dst are same issue #249 2024-09-13 10:34:07 +08:00
Sun Yimin
ee312709aa
sm4: ppc64x, cbc init #249 2024-09-13 09:49:44 +08:00
Sun Yimin
15f4ac4535
sm4: ppc64x, fix ecb #249 2024-09-12 16:54:39 +08:00
Sun Yimin
58685cc430
sm4: ppc64x, fix duplicated definition of symbol github.com/emmansun/gmsm/sm4.rcon 2024-09-12 16:43:14 +08:00
Sun Yimin
ac95feaf4f
sm4: ppc64x, ecb fix compile issue #249 2024-09-12 16:40:58 +08:00
Sun Yimin
a9459164b0
sm4: ppc64x, fix ecb #249 2024-09-12 16:38:05 +08:00
Sun Yimin
062662836a
sm4: ppc64x, ecb 2024-09-12 16:22:35 +08:00
Sun Yimin
5d9aa05746
sm4: ppc64x, fix bug #249 2024-09-12 16:08:15 +08:00
Sun Yimin
11db64eb35
sm4: ppc64x, fix duplicated definition of symbol github.com/emmansun/gmsm/sm4.rcon 2024-09-12 16:00:47 +08:00
Sun Yimin
2f048ffbdf
sm4: ppc64x, refactor #249 2024-09-12 15:53:53 +08:00
Sun Yimin
0455a06386
sm4: ppc64x, enable ctr mode parallel 2024-09-12 13:05:03 +08:00
Sun Yimin
7aae08ff76
sm4: ppc64x, fix encryptBlocksAsm #249 2024-09-12 11:50:39 +08:00
Sun Yimin
66a9dcdd81
sm4: ppc64x, fix encryptBlocksAsm #249 2024-09-12 11:31:19 +08:00
Sun Yimin
38282cd292
sm4: make sure test all asm codes 2024-09-12 11:20:50 +08:00
Sun Yimin
91af41952b
fix copy/paster error 2024-09-12 10:53:35 +08:00
Sun Yimin
777ab60dd0
sm4: is it really related to ctr change? 2024-09-12 10:44:56 +08:00
Sun Yimin
b8eeda2309
sm4: ppc64x, Test Force SM4 Single Block with AES-NI 2024-09-12 10:33:26 +08:00
Sun Yimin
ae6a1a486d
sm4: ppc64x, enable ctr mode parallel #249 2024-09-12 10:18:32 +08:00
Sun Yimin
6b0a557be1
sm4: ppc64x, merge the implementation to cipher_asm 2024-09-12 10:12:37 +08:00
Sun Yimin
eb9ef3ad93
sm4: ppc64x, fix SM4_ROUND issue #249 2024-09-12 08:52:59 +08:00
Sun Yimin
0c8671775f
sm4: ppc64x, missing address change 2024-09-12 08:47:10 +08:00
Sun Yimin
759a985cfa
sm4: ppc64x, fix test case 2024-09-12 08:29:15 +08:00
Sun Yimin
0dba1200a5
sm4: ppc64x, missing macro #249 2024-09-12 08:19:15 +08:00
Sun Yimin
420b9e9dfd
sm4: ppc64x, missing macro #249 2024-09-12 08:16:51 +08:00
Sun Yimin
8c9a6283fe
sm4: ppc64x, missing macro 2024-09-12 08:16:10 +08:00
Sun Yimin
8de52628d2
sm4: ppc64x, encryptBlockAsm #249 2024-09-12 08:14:06 +08:00
Sun Yimin
c279984922
sm4: ppc64x, use NIBBLE_MASK as round key 2024-09-11 16:36:35 +08:00
Sun Yimin
7cc5130380
sm4: ppc64x, use VSRD to replace VSRW 2024-09-11 16:29:45 +08:00
Sun Yimin
69d3481edc
sm4: ppc64x, missing fk 2024-09-11 16:09:48 +08:00
Sun Yimin
40486134f8
check input data 2024-09-11 15:35:06 +08:00
Sun Yimin
b8e15b50af
ppc64x, make sure sm4 sbox first 2024-09-11 14:58:51 +08:00
Sun Yimin
942c363ad0
sm4: ppc64x, fix m1l, m1h, m2l, m2h 2024-09-11 14:51:12 +08:00
Sun Yimin
5956841dd3
test ppc64x aes sbox 2024-09-11 13:06:21 +08:00
Sun Yimin
786098ac6a
test AFFINE_TRANSFORM 2024-09-11 11:34:56 +08:00
Sun Yimin
9a6e66c4eb
fix typo 2024-09-11 11:15:53 +08:00
Sun Yimin
73243191f3
sm4: ppc4x, test sm4 box 2024-09-11 11:13:25 +08:00
Sun Yimin
8014d53c57
sm4: ppc64x, update inverse shift rows value according VCIPHERLAST test result 2024-09-11 10:48:40 +08:00
Sun Yimin
57b724eb0e
test VCIPHERLAST 2024-09-11 10:24:30 +08:00
Sun Yimin
44e6ef3444
sm4: ppc64x, use ZERO as VCIPHERLAST round key 2024-09-11 10:18:46 +08:00
Sun Yimin
3491cb091a
test VNAND 2024-09-11 09:45:08 +08:00
Sun Yimin
6c62c14405
sm4: try VCIPHERLAST 2024-09-11 09:01:42 +08:00
Sun Yimin
69e3749a10
sm4: try VNAND 2024-09-11 08:50:40 +08:00
Sun Yimin
f6d2e319c1
sm4: fix compile error 2024-09-11 08:31:33 +08:00
Sun Yimin
45c90c33cd
sm4: reverse inverse shift rows byte order 2024-09-11 08:29:44 +08:00
Sun Yimin
2ca0421085
try VNAND 2024-09-11 08:23:46 +08:00
Sun Yimin
4f60a230f0
sm3: ppc64, reverse m1,m2 byte order 2024-09-11 08:21:12 +08:00
Sun Yimin
d2adcd78b0
Update asm_ppc64x.s 2024-09-10 22:37:31 +08:00
Sun Yimin
98e2f4a852
sm4: ppc64x fix T2 issue 2024-09-10 21:54:08 +08:00
Sun Yimin
086ea1267b
sm4: ppc64x expand key debug 3 2024-09-10 17:46:54 +08:00
Sun Yimin
5a8c253a5a
sm4: ppc64x expand key debug 2 2024-09-10 17:41:31 +08:00
Sun Yimin
c21ab2d9c8
sm4: ppc64x expand key debug 1 2024-09-10 17:38:12 +08:00
Sun Yimin
742bdcc1aa
sm4: ppc64x expand key fix 3 2024-09-10 17:04:41 +08:00
Sun Yimin
82efc4b40f
sm4: ppc64x expand key fix 2 2024-09-10 17:00:39 +08:00
Sun Yimin
8cd7748b00
sm4: ppc64x expand key fix 1 2024-09-10 16:59:16 +08:00
Sun Yimin
0333280ef1
sm4: ppc64x expandkey init 2024-09-10 16:55:33 +08:00
Sun Yimin
4fd59a1901
Update README 2024-09-10 13:04:26 +08:00
Sun Yimin
8c2dd95a5c
sm3: s390x block, init 2024-09-10 09:00:38 +08:00
Sun Yimin
8cb35658e4
Merge pull request #247 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.27.0
build(deps): bump golang.org/x/crypto from 0.26.0 to 0.27.0
2024-09-10 08:04:23 +08:00
dependabot[bot]
53164026d0
build(deps): bump golang.org/x/crypto from 0.26.0 to 0.27.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.26.0 to 0.27.0.
- [Commits](https://github.com/golang/crypto/compare/v0.26.0...v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 23:53:05 +00:00
Sun Yimin
60275adc78
Merge pull request #246 from emmansun/dependabot/go_modules/golang.org/x/sys-0.25.0
build(deps): bump golang.org/x/sys from 0.24.0 to 0.25.0
2024-09-10 07:52:01 +08:00
dependabot[bot]
cc0462d8a0
build(deps): bump golang.org/x/sys from 0.24.0 to 0.25.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.24.0 to 0.25.0.
- [Commits](https://github.com/golang/sys/compare/v0.24.0...v0.25.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 23:23:33 +00:00
Sun Yimin
a564207436
sm3: ppc64x block, remove useless code and add comments #245 2024-09-09 17:28:42 +08:00
Sun Yimin
86d7648b6f
sm3: ppc64x block, load w change 2024-09-09 16:39:18 +08:00
Sun Yimin
2d8b0fde8e
sm3: ppc64x block, fix compile issue 1 #245 2024-09-09 15:50:56 +08:00
Sun Yimin
ec3aff95f9
sm3: ppc64x block init #245 2024-09-09 15:47:42 +08:00
Sun Yimin
28d56b2ce2
sm3: ppcx64, align address access mode 2024-09-09 08:52:34 +08:00
Sun Yimin
79e33e2970
sm3: ppc64x, improve code readability 2024-09-09 08:46:02 +08:00
Sun Yimin
b606bd773f
sm3: ppc64x, update comments 2024-09-06 17:52:13 +08:00
Sun Yimin
0799942ef9
sm3: ppc64x, s390x mult4 add comments 2024-09-06 17:20:01 +08:00
Sun Yimin
2d3220793c
sm3: ppc64x, fix general purpose register usage issue 2024-09-06 15:19:23 +08:00
Sun Yimin
fa9aba2cd6
sm3: test copyResultsBy4 2024-09-06 15:03:53 +08:00
Sun Yimin
b95cbabf8b
sm3: ppc64x, test more 2024-09-06 14:56:18 +08:00
Sun Yimin
7a84c6fd29
sm3: add copyResultsBy4 test case 2024-09-06 14:19:40 +08:00
Sun Yimin
664f5dcae3
fix LOAD_T 2024-09-06 13:49:01 +08:00
Sun Yimin
76c0cc93d9
fix LOAD_T 2024-09-06 13:38:10 +08:00
Sun Yimin
47ac403b9a
test load constant T 2024-09-06 13:35:24 +08:00
Sun Yimin
df0242f4fc
test load constant T 2024-09-06 13:32:23 +08:00
Sun Yimin
66d356888b
split rotl 19 to rotl 10 then rotl 9 2024-09-06 13:28:12 +08:00
Sun Yimin
adc8702ad7
test VSPLTISW scope 2024-09-06 13:22:41 +08:00
Sun Yimin
72a838fa56
sm3: ppc64x, kdf mult by 4, 4 2024-09-06 13:12:16 +08:00
Sun Yimin
5d9a4eb11d
sm3: ppc64x, kdf mult by 4, 3 2024-09-06 11:16:21 +08:00
Sun Yimin
0cfb42fb8b
sm3: ppc64x, kdf mult by 4, 2 2024-09-06 11:14:27 +08:00
Sun Yimin
8a33e6278b
sm3: ppc64x, kdf mult by 4, 1 2024-09-06 11:08:41 +08:00
Sun Yimin
e3c178c724
sm3: ppc64x, remove useless files 2024-09-06 11:06:13 +08:00
Sun Yimin
077b115c29
sm3: ppc64x, kdf mult by 4 2024-09-06 11:05:26 +08:00
Sun Yimin
6e8a3cc832
sm3: ppc64x, try rotate shift left 2024-09-06 09:46:07 +08:00
Sun Yimin
42780c9671
fix instruction 2024-09-06 09:43:11 +08:00
Sun Yimin
d1fdc2c725
sm3: ppc64, test rotatle left shift 2024-09-06 09:42:35 +08:00
Sun Yimin
9b71462763
sm3: ppc64x, fix copyResultsBy4 2024-09-06 08:52:38 +08:00
Sun Yimin
0f55f2e6c4
sm3: ppc64x, fix copyResultsBy4 2024-09-06 08:48:53 +08:00
Sun Yimin
066dcaa3e8
sm3: ppc64x, fix copyResultsBy4 2024-09-06 08:45:15 +08:00
Sun Yimin
1863212148
sm3: ppc64x, try LXVW4X STXVW4X 2024-09-06 08:19:02 +08:00
Sun Yimin
d2b1d1b0d6
sm3: ppc64x copyResultsBy4 2024-09-05 17:33:12 +08:00
Sun Yimin
25c20a974a
sm3: ppc64x transpose 4x4 matrix 1 2024-09-05 16:43:24 +08:00
Sun Yimin
69be0eae4c
debug ppc64le byte order 3 2024-09-05 15:37:55 +08:00
Sun Yimin
bfd84510d4
debug ppc64le byte order 2 2024-09-05 15:11:40 +08:00
Sun Yimin
e7299cda75
debug ppc64le byte order 2024-09-05 14:54:46 +08:00
Sun Yimin
379dbdd3fb
sm3: ppc64x, transpose matrix fix 2024-09-05 13:46:41 +08:00
Sun Yimin
bc4b8e691f
sm3: ppc64x debug 1 2024-09-05 13:31:23 +08:00
Sun Yimin
eacd58c06c
sm3: ppc64, test power9 instructions 2024-09-05 13:03:23 +08:00
Sun Yimin
f04666b427
ci: ppc64le test -v 2024-09-05 12:57:47 +08:00
Sun Yimin
f4015ea2cf
sm3: ppc64x transposeMatrix 2024-09-05 12:55:13 +08:00
Sun Yimin
62c8b42c68
sm3: update file format 2024-09-04 17:47:15 +08:00
Sun Yimin
6d620a257f
sm3: kdf arm64, fix marcro issue 2024-09-04 16:44:57 +08:00
Sun Yimin
8e050f1064
sm3: kdf arm64 optimization 2024-09-04 16:34:43 +08:00
Sun Yimin
bda03f4f43
sm3: kdf s390x 2024-09-04 16:04:14 +08:00
Sun Yimin
8fad760377
message schedule 2 2024-09-04 16:01:56 +08:00
Sun Yimin
5d7d20c335
test message schedule 2024-09-04 15:48:46 +08:00
Sun Yimin
f6f7cb7c73
test loadWordByIndex 2024-09-04 15:44:53 +08:00
Sun Yimin
eb0e43e699
test VLREPF VERLLF 2024-09-04 15:31:54 +08:00
Sun Yimin
a410cef060
debug blockMultBy4 4 2024-09-04 15:12:12 +08:00
Sun Yimin
d79b6b3e14
debug blockMultBy4 3 2024-09-04 14:49:26 +08:00
Sun Yimin
d18ea90a25
debug blockMultBy4 2 2024-09-04 14:35:48 +08:00
Sun Yimin
2657fb2738
debug blockMultBy4 1 2024-09-04 13:54:38 +08:00
Sun Yimin
519cf3fe48
try non-R0 2024-09-04 13:46:55 +08:00
Sun Yimin
9569115aa8
use VLREPF 2024-09-04 13:36:16 +08:00
Sun Yimin
96073ed701
VREPF VREPIF VLREPF 2024-09-04 13:34:30 +08:00
Sun Yimin
9666c927fa
use other instructions to implement VREPIF 2024-09-04 13:20:22 +08:00
Sun Yimin
0223ff88d1
test VREPIF 2 2024-09-04 13:15:36 +08:00
Sun Yimin
845ad80aa1
test VREPIF 2024-09-04 13:13:14 +08:00
Sun Yimin
5aabb44ba2
sm3: kdf s390x fix 4 2024-09-04 11:46:33 +08:00
Sun Yimin
f03d40ea71
sm3: kdf s390x fix 3 2024-09-04 11:40:08 +08:00
Sun Yimin
4c6fba843f
sm3: kdf s390x fix 2 2024-09-04 11:37:31 +08:00
Sun Yimin
10620d5048
sm3: kdf s390x fix 1 2024-09-04 11:35:54 +08:00
Sun Yimin
c88b59bf5b
sm3: kdf s390x, remove useless method 2024-09-04 11:27:59 +08:00
Sun Yimin
602194335c
sm3: s390x kdf v1 2024-09-04 11:24:56 +08:00
Sun Yimin
b2861782aa
sm3: copyResultsBy4 s390x test 2024-09-04 08:02:41 +08:00
Sun Yimin
a3fa174e71
sm3: s390x copyResultsBy4 2024-09-04 07:58:07 +08:00
Sun Yimin
75d3974162
sm3: s390x, transpose matrix version 1 2024-09-03 17:46:16 +08:00
Sun Yimin
520bc395c9
debug 10 2024-09-03 17:41:06 +08:00
Sun Yimin
73172852b5
debug 9 2024-09-03 17:36:35 +08:00
Sun Yimin
899e51114d
debug 8 2024-09-03 17:30:13 +08:00
Sun Yimin
a61a135931
debug 7 2024-09-03 17:24:18 +08:00
Sun Yimin
41e630166f
debug 6 2024-09-03 17:18:45 +08:00
Sun Yimin
e475dafc73
debug 5 2024-09-03 17:12:12 +08:00
Sun Yimin
335947eb5a
debug 4 2024-09-03 16:16:56 +08:00
Sun Yimin
7dfec000f2
debug 3 2024-09-03 16:10:35 +08:00
Sun Yimin
c152e9ef42
debug 2 2024-09-03 15:51:16 +08:00
Sun Yimin
40bc2f5f84
debug 1 2024-09-03 15:20:10 +08:00
Sun Yimin
fda15351c7
sm3: s390x fix compile issue 2024-09-03 14:34:53 +08:00
Sun Yimin
29d315f316
ci: enable s390x sm3 2024-09-03 14:29:48 +08:00
Sun Yimin
e626a00982
sm3: s390x transpose matrix poc 2024-09-03 14:28:14 +08:00
Sun Yimin
c7a68d9246
internal/sm2ec: ppc64le,
Improve VMULT_ADD code readability
2024-09-03 12:57:34 +08:00
Sun Yimin
236f23b24c
internal/sm2ec: ppc64le, p256Sqr, remove stange code 2024-09-03 08:58:47 +08:00
Sun Yimin
c88486ea0a
internal/sm2ec: ppc64le, guess stack offset 2024-09-03 08:51:44 +08:00
Sun Yimin
e1b60feeb5
internal/sm2ec: ppc64le, change p256PointAddAffineAsm's stack 2024-09-03 08:46:26 +08:00
Sun Yimin
dfcafd31b3
internal/sm2ec: ppc64le, p256PointAddAsm reduce memory acesss 2024-09-03 08:23:21 +08:00
Sun Yimin
235382a457
internal/subtle: fix riscv64 2024-09-02 13:18:08 +08:00
Sun Yimin
3ede9024a5
internal/subtle: simple riscv64 2024-09-02 13:13:16 +08:00
Sun Yimin
8a2ba16639
internal/cryptotest: add tests for the cipher.AEAD interface 2024-08-30 16:25:25 +08:00
Sun Yimin
fdf83a1ee8
internal/sm2ec: ppc64le, redefine K0 constant 2024-08-30 16:21:03 +08:00
Sun Yimin
c8384dd226
internal/sm2ec: ppc64le, fix comments #237 2024-08-29 17:38:49 +08:00
Sun Yimin
68f37d7934
internal/sm2ec: ppc64le, change to use VMULUWM as WMLF 2024-08-29 14:05:47 +08:00
Sun Yimin
79efc657e0
internal/sm2ec: ppc64le, simplified MK0 calculation 2024-08-29 13:29:03 +08:00
Sun Yimin
0c5dc07ba7
internal/sm2ec: fix ppc64le typo 2024-08-29 13:21:06 +08:00
Sun Yimin
7e768828e0
check failed detail 2024-08-29 13:13:50 +08:00
Sun Yimin
38f25df5ce
internal/sm2ec: fix ppc64le ord 4 2024-08-29 11:27:44 +08:00
Sun Yimin
d92f6afea1
internal/sm2ec: fix ppc64le incorrect K0 constant 2024-08-29 10:23:41 +08:00
Sun Yimin
5ddd288221
internal/sm2ec: fix ppc64le 3 2024-08-29 10:16:55 +08:00
Sun Yimin
7b8431c101
internal/sm2ec: fix ppc64le 2 2024-08-29 10:09:25 +08:00
Sun Yimin
95f78a8497
internal/sm2ec: fix ppc64le 2024-08-29 10:06:10 +08:00
Sun Yimin
c198fa8abc
internal/sm2ec: ppc64le order mul/sqr 2024-08-29 10:02:16 +08:00
Sun Yimin
f0b36b70ce
internal/sm2ec: s390x, try to use VLM/VSTM #235 2024-08-29 08:33:35 +08:00
Sun Yimin
a32ca8fa14
internal/sm2ec: ppc64le, fix address issue 2024-08-28 13:52:34 +08:00
Sun Yimin
a83f85f561
internal/sm2ec: ppc64le, fix SEL 2024-08-28 13:48:02 +08:00
Sun Yimin
e8424e9b26
internal/sm2ec: ppc64le, typo 2024-08-28 13:44:50 +08:00
Sun Yimin
35d5ddeaf4
internal/sm2ec: ppc64le, change p256NegCond to constant-time 2024-08-28 13:42:06 +08:00
Sun Yimin
b69000109b
internal/subtle: s390x, not use VLM/VSTM first, should be address mode issue 2024-08-28 13:27:22 +08:00
Sun Yimin
45584ccaa6
internal/subtle: apply VLM/VSTM in non-loop 2024-08-28 13:18:42 +08:00
Sun Yimin
40bd384f21
internal/subtle: s390x, use VLM/VSTM in loop 2024-08-28 13:12:57 +08:00
Sun Yimin
4ad4fb4136
internal/subtle: s390x, fix typo 2024-08-28 13:10:15 +08:00
Sun Yimin
f366964a77
internal/subtle: s390x, check if VLM/VSTM issue 2024-08-28 13:08:26 +08:00
Sun Yimin
a2295b993d
internal/subtle: s390x, add quick end checking 2024-08-28 10:16:08 +08:00
Sun Yimin
eb36af59e5
internal/subtle: s390x, handle tail 2024-08-28 10:13:59 +08:00
Sun Yimin
e3fba2448c
internal/subtle: s390x rollback first 2024-08-28 09:59:52 +08:00
Sun Yimin
d3727e7130
align address mode 2024-08-28 09:42:12 +08:00
Sun Yimin
ae43444a63
list all fail cases 2024-08-28 09:19:47 +08:00
Sun Yimin
eb1b01a916
address model issue? 2024-08-28 08:56:01 +08:00
Sun Yimin
c0055c1fb4
intenal/subtle: s390x use VLM/VSTM 2024-08-28 08:38:36 +08:00
Sun Yimin
8be54ddf9e
internal/subtle: port ppc64x from golang 2024-08-28 08:18:43 +08:00
Sun Yimin
7ab7bb6aca
smx509: 兼容OpenSSL3不一致的公钥算法OID 2024-08-27 17:43:59 +08:00
Sun Yimin
3166f5e06b
update documents 2024-08-27 17:21:00 +08:00
Sun Yimin
ba9e49e7a2
internal/sm2ec: ppc64le full test 2024-08-27 15:45:28 +08:00
Sun Yimin
ffb69629c0
fix typo 2024-08-27 15:16:17 +08:00
Sun Yimin
187a4f7b80
internal/sm2ec: enable ppc64le step 1 2024-08-27 15:14:15 +08:00
Sun Yimin
e1e485c32d
fix test case 2024-08-27 14:06:19 +08:00
Sun Yimin
2f1740ff26
debug 2 2024-08-27 14:03:27 +08:00
Sun Yimin
998b9f6872
debug 2024-08-27 13:32:16 +08:00
Sun Yimin
4f6887c39c
do not use R1 2024-08-27 13:24:19 +08:00
Sun Yimin
77c51c2295
internal/sm2ec: ppc64le kick start 2024-08-27 13:18:30 +08:00
Sun Yimin
5af95316f0
internal/sm2ec: s390x uses VLM/VSTM batch 4 2024-08-27 08:56:48 +08:00
Sun Yimin
849deaf90a
fix batch 3 2024-08-27 08:31:58 +08:00
Sun Yimin
4fe05e6f85
fix batch 3 2024-08-27 08:29:26 +08:00
Sun Yimin
189dcd4ca0
internal/sm2ec: s390x uses VLM/VSTM batch 3 2024-08-27 08:25:47 +08:00
Sun Yimin
260c84eeb4
internal/sm2ec: s390x uses VLM/VSTM optimize load/store batch 2 2024-08-26 17:50:17 +08:00
Sun Yimin
9034606fc7
internal/sm2ec: s390x uses VLM/VSTM optimize load/store 2024-08-26 17:39:02 +08:00
Sun Yimin
f0165e8bb2
internal/sm2ec: s390x fix VLM/VSTM 2024-08-26 17:31:22 +08:00
Sun Yimin
383d74ed93
internal/sm2ec: s390x try VLM/VSTM 2024-08-26 17:25:55 +08:00
Sun Yimin
6852a2c51f
CI: s390x enable sha1 for test 2024-08-26 17:12:57 +08:00
Sun Yimin
e12f17a35a
kdf: kdf 64bit panic test exclude s390x first 2024-08-26 17:07:24 +08:00
Sun Yimin
b9bfc48626
internal/sm2ec: s390x p256SelectAffine extra loop 2024-08-26 16:56:15 +08:00
Sun Yimin
155fd15b42
test 3 2024-08-26 16:53:45 +08:00
Sun Yimin
ca41e7e4a9
test 2 2024-08-26 16:49:53 +08:00
Sun Yimin
aebb6b9898
test 2024-08-26 16:42:02 +08:00
Sun Yimin
0b39d77338
test s390x scalarmult 2024-08-26 16:31:10 +08:00
Sun Yimin
a9a7471553
test 2024-08-26 15:47:22 +08:00
Sun Yimin
a85384aca6
test s390x sm2 functions first 2024-08-26 15:44:13 +08:00
Sun Yimin
626cf9cfed
test s390x sm2 functions 2024-08-26 15:14:19 +08:00
Sun Yimin
013e11cc83
s390 test all 2024-08-26 14:54:44 +08:00
Sun Yimin
94a4b08155
internal/sm2ec: fix s390x p256Select 2024-08-26 14:52:48 +08:00
Sun Yimin
c26709d795
internal/sm2ec: make sure point add is correct 2024-08-26 14:37:10 +08:00
Sun Yimin
700edb923d
internal/sm2ec: make sure point double is correct 2024-08-26 14:28:15 +08:00
Sun Yimin
d4a812927d
debug 2 2024-08-26 13:48:15 +08:00
Sun Yimin
528662c327
debug 2024-08-26 13:43:27 +08:00
Sun Yimin
c50b71f0af
internal/sm2ec: test point double 6 times 2024-08-26 13:20:43 +08:00
Sun Yimin
ebe5413d1e
internal/sm2ec: change order for s390x 2024-08-26 11:45:46 +08:00
Sun Yimin
05f3bcb57c
internal/sme2c: enable s390x asm optimization 2024-08-26 11:31:15 +08:00
Sun Yimin
53508a6644
internal/sm2ec: s390x fix macro issue 2024-08-26 10:59:30 +08:00
Sun Yimin
68d387a75b
internal/sm2ec: s390x p256Mul 2024-08-26 10:53:41 +08:00
Sun Yimin
64bb76b3d9
internal/sm2ec: try VLEF, fix issue 2024-08-23 17:49:51 +08:00
Sun Yimin
509da71c7c
internal/sm2ec: try VLEF 2024-08-23 17:46:14 +08:00
Sun Yimin
9195b3049d
internal/sm2ec: s390x p256OrdSqr 2024-08-23 17:43:18 +08:00
Sun Yimin
807c505e0c
internal/sm2ec: enable s390x p256OrdMul 2024-08-23 17:00:01 +08:00
Sun Yimin
ba58a2e3ee
internal/sm2ec: test s390x p256OrdMul 2024-08-23 16:50:23 +08:00
Sun Yimin
40549083c1
fix test case 2024-08-23 16:15:50 +08:00
Sun Yimin
98eee001a4
fix offset 2024-08-23 16:05:14 +08:00
Sun Yimin
495f8ae7a4
internal/sm2ec: fix s390x p256FromMont 2024-08-23 16:01:41 +08:00
Sun Yimin
bf891d841e
use efforf instead of fatalf 2024-08-23 15:29:36 +08:00
Sun Yimin
223d593817
fix test cases 2024-08-23 15:25:42 +08:00
Sun Yimin
eea60eea91
internal/sm2ec: fix address issue 2024-08-23 15:07:22 +08:00
Sun Yimin
3578343e11
internal/sm2ec: fix s390x p256OrdReduce 2024-08-23 15:03:00 +08:00
Sun Yimin
72bdf4ba55
fix s390x action 2024-08-23 14:59:32 +08:00
Sun Yimin
b5309dbfc9
fix CI qemu action issue 2024-08-23 14:58:40 +08:00
Sun Yimin
90f0215a94
update s390x action 2024-08-23 14:45:03 +08:00
Sun Yimin
aa9a702b1e
internal/sm2ec: s390x p256FromMont 2024-08-23 14:42:49 +08:00
Sun Yimin
49ff44ddd7
internal/sm2ec/fiat: add inversion test with divsteps 2024-08-20 13:09:17 +08:00
Sun Yimin
b6821a6853
internal/subtle: try s390x vector 2024-08-20 10:02:42 +08:00
Sun Yimin
6925a64c6c
internal/subtle: s390x 2024-08-19 17:46:47 +08:00
Sun Yimin
1f2a93916b
internal/sm2ec: fix order asm inverse 2024-08-19 14:48:19 +08:00
Sun Yimin
dd5b54f503
internal/sm2ec: replace P256OrdInverse with generated code 2024-08-19 13:02:02 +08:00
Sun Yimin
2f0f4745d7
smx509: add t.Helper calls to test helpers 2024-08-16 09:23:25 +08:00
Sun Yimin
6926113a10
sm2ec/fiat: regenerate to include more functions and scalar/order related 2024-08-14 10:38:13 +08:00
Sun Yimin
b7f95a5a9f
sm2: typo 2024-08-13 13:35:45 +08:00
Sun Yimin
4517d00cc1
sm2: fix RecoverPublicKeysFromSM2Signature 2024-08-13 13:34:51 +08:00
Sun Yimin
4c7cf989c7
Merge pull request #234 from emmansun/dependabot/go_modules/golang.org/x/sys-0.24.0
build(deps): bump golang.org/x/sys from 0.23.0 to 0.24.0
2024-08-13 09:13:05 +08:00
dependabot[bot]
c1bc68aa9d
build(deps): bump golang.org/x/sys from 0.23.0 to 0.24.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.23.0 to 0.24.0.
- [Commits](https://github.com/golang/sys/compare/v0.23.0...v0.24.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-13 00:36:26 +00:00
Sun Yimin
7724ae48da
Merge pull request #233 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.26.0
build(deps): bump golang.org/x/crypto from 0.25.0 to 0.26.0
2024-08-13 08:35:21 +08:00
dependabot[bot]
8da13aec03
build(deps): bump golang.org/x/crypto from 0.25.0 to 0.26.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.25.0 to 0.26.0.
- [Commits](https://github.com/golang/crypto/compare/v0.25.0...v0.26.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-12 23:35:55 +00:00
Sun Yimin
28920ff1a8
Merge pull request #232 from emmansun/dependabot/go_modules/golang.org/x/sys-0.23.0
build(deps): bump golang.org/x/sys from 0.22.0 to 0.23.0
2024-08-06 07:26:41 +08:00
dependabot[bot]
96e0a9baf0
build(deps): bump golang.org/x/sys from 0.22.0 to 0.23.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.22.0 to 0.23.0.
- [Commits](https://github.com/golang/sys/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-05 23:23:15 +00:00
Sun Yimin
a5d489ee59
internal/cryptotest: add tests for the cipher.Stream interface 2024-08-05 11:40:04 +08:00
Sun Yimin
1b512e5772
internal/cryptotest: add tests for the hash.Hash cipher.BlockMode cipher.Block interfaces 2024-08-02 13:02:25 +08:00
Sun Yimin
95b644238f
README update 2024-07-26 17:42:58 +08:00
Sun Yimin
4b19c80ffc
doc: pkcs7 supplement detached signature 2024-07-26 09:53:00 +08:00
Sun Yimin
ba1836fa45
pkcs: supplement test cases 2024-07-10 14:47:27 +08:00
Sun Yimin
d5b39e6176
pkcs: fix error message issue 2024-07-09 12:58:47 +08:00
Sun Yimin
eb72185fff
pkcs: pbes initial supports GM/T 0091-2020 2024-07-09 12:56:02 +08:00
Sun Yimin
fa39b1fd7a
doc: update sm2.md 2024-07-09 10:00:12 +08:00
Sun Yimin
7a545ef791
Merge pull request #229 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.25.0
build(deps): bump golang.org/x/crypto from 0.24.0 to 0.25.0
2024-07-09 07:51:55 +08:00
dependabot[bot]
681c2d6612
build(deps): bump golang.org/x/crypto from 0.24.0 to 0.25.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.24.0 to 0.25.0.
- [Commits](https://github.com/golang/crypto/compare/v0.24.0...v0.25.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-08 23:17:46 +00:00
Sun Yimin
fbcf51a46f
Merge pull request #230 from emmansun/dependabot/go_modules/golang.org/x/sys-0.22.0
build(deps): bump golang.org/x/sys from 0.21.0 to 0.22.0
2024-07-09 07:17:08 +08:00
dependabot[bot]
59c852abcb
build(deps): bump golang.org/x/sys from 0.21.0 to 0.22.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.21.0 to 0.22.0.
- [Commits](https://github.com/golang/sys/compare/v0.21.0...v0.22.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-08 23:14:50 +00:00
Sun Yimin
d7c02ead50
pkcs8: predefine some common errors 2024-07-08 17:00:18 +08:00
Sun Yimin
21ff9aa3ab
pkcs8: fix test case 2024-07-05 16:12:19 +08:00
Sun Yimin
41f4ec0e83
pkcs8: support legacy PBES1 algorithms (parse only) 2024-07-05 16:07:38 +08:00
Sun Yimin
ff1269c9dc
doc: update pkcs12.md 2024-07-05 15:31:13 +08:00
Sun Yimin
2c87cdf8d8
pkcs: refactoring, extract pbes2 from pkcs8 2024-07-04 17:29:44 +08:00
Sun Yimin
ffddbdcfec
doc: supplement PBMAC in pkcs12.md 2024-07-03 11:11:09 +08:00
Sun Yimin
58196f9364
doc: update pkcs12.md 2024-07-03 08:20:11 +08:00
Sun Yimin
8b0ad54238
doc: add zuc.md 2024-06-28 12:54:01 +08:00
Sun Yimin
dcb94c112f
pkcs8: add example code for encrypted to plaintext 2024-06-27 11:17:31 +08:00
Sun Yimin
2ead6d523d
doc: add pkcs12 2024-06-25 17:41:14 +08:00
Sun Yimin
800119e2d9
kdf: add sha256 test cases 2024-06-24 08:35:53 +08:00
Sun Yimin
9382886282
pkcs7: polish, improve maintainability 2024-06-21 18:00:21 +08:00
Sun Yimin
dc66ca673e
pkcs7: follow GB/T 35275-2017 9.1 strictly 2024-06-20 11:49:10 +08:00
Sun Yimin
0445d16e97
smx509: fix CSRResponse sign certs handle issue 2024-06-18 11:43:20 +08:00
Sun Yimin
a1de6312b4
doc: pkcs7 fix table display issue 2024-06-17 17:52:37 +08:00
Sun Yimin
5b3d0a424e
doc: suppliement pkcs7 document and comments 2024-06-17 17:42:00 +08:00
Sun Yimin
1ef4cf9510
smx509: improve test coverage 2024-06-13 17:44:32 +08:00
Sun Yimin
6ba367a255
smx509: support CSRRespose handling 2024-06-12 17:49:37 +08:00
Sun Yimin
36eaeabd95
doc: refine sm2/cfca documents 2024-06-12 10:40:00 +08:00
Sun Yimin
1b34247549
doc: fix reference doc name 2024-06-11 17:50:04 +08:00
Sun Yimin
2f586539d4
doc: CFCA互操作性指南 2024-06-11 17:42:19 +08:00
Sun Yimin
4db3046001
pkcs7: support older CFCA integration #225 2024-06-11 11:01:05 +08:00
Sun Yimin
23081971e8
pkcs7: support CFCA legacy SM2 envelope message #225 2024-06-10 19:46:51 +08:00
Sun Yimin
fbe4073a46
sm3: fix slice bound issue #226 2024-06-10 18:45:26 +08:00
Sun Yimin
5a9d7e1b67
dep: upgrade 2024-06-07 16:20:44 +08:00
Sun Yimin
212fae1dda
drbg: add comments 2024-06-05 17:47:56 +08:00
Sun Yimin
95bc8792f8
drbg: rollback hash drbg change 2024-06-05 13:07:29 +08:00
Sun Yimin
10a97b4c51
drbg: support NIST HMAC-DRBG 2 2024-06-05 13:01:28 +08:00
Sun Yimin
dfc45df2d8
drbg: support NIST HMAC-DRBG 2024-06-05 13:00:44 +08:00
Sun Yimin
b434b5f373
doc: sm2应用扩展 2024-06-04 11:41:58 +08:00
Sun Yimin
cad5d3504e
sm2: public recover from signature 2 2024-06-04 08:26:51 +08:00
Sun Yimin
126ee25d2a
sm4: arm64 asm redefine register usage and const loading 2024-06-03 17:50:44 +08:00
Sun Yimin
7bb7903ce2
sm2: recover public keys 2024-06-01 10:31:29 +08:00
Sun Yimin
63affe5127
sm2: recover public keys from signature 2024-05-31 18:30:58 +08:00
Sun Yimin
81b0c7f5ae
internal/bigmod: make CmpGeq public 2024-05-31 18:13:14 +08:00
Sun Yimin
91932efc27
correct comments 2024-05-30 17:56:23 +08:00
Sun Yimin
9491f5db11
upgrade actions/setup-go to v5 2024-05-29 12:57:54 +08:00
Sun Yimin
1596440d53
trigger CI action 2024-05-29 10:27:51 +08:00
Sun Yimin
c3f33f87ba
ci: fix codecov action issue 2024-05-29 08:47:46 +08:00
Sun Yimin
1cf81a8e7c
sm3: multi-blocks refactoring 2024-05-28 17:44:12 +08:00
Sun Yimin
2c688bb9d3
subtle: align byte equal alg 2024-05-28 17:33:48 +08:00
Sun Yimin
5b1df00c92
sm3: fix arm64 issue 2 2024-05-27 17:52:54 +08:00
Sun Yimin
ff6afd5a96
sm3: fix arm64 issue 2024-05-27 17:49:13 +08:00
Sun Yimin
4d69f363f5
sm3-kdf: continue to improve performance 2024-05-27 17:42:17 +08:00
Sun Yimin
ea0884c4a0
doc: update sm2 encryption performance 2024-05-26 11:20:59 +08:00
Sun Yimin
238c0a3634
kdf-sm3: add (8+4+1) test cases and reduce last round instructions 2024-05-24 17:44:17 +08:00
Sun Yimin
3ede319900
sm3: mult 4 way rename some macros 2024-05-24 08:24:09 +08:00
Sun Yimin
74754d50d7
x509: fix test cases, disable sm2withsm3 mixed with others #223 2024-05-23 21:04:30 +08:00
Sun Yimin
8787268d3d
Update x509.go 2024-05-23 20:34:40 +08:00
Sun Yimin
6762238407
x509: rollback some change first #223 2024-05-23 17:49:43 +08:00
Sun Yimin
7c46d7b977
x509: sync with sdk #223 2024-05-23 17:35:56 +08:00
Sun Yimin
ed0b2551ed
kdf-sm3: mult 8 way avx2 version #222 2024-05-23 13:09:16 +08:00
Sun Yimin
2e05c453c8
kdf-sm3: mult by 4 way optimization 2024-05-23 10:38:06 +08:00
Sun Yimin
499415a21d
Update test_qemu.yml 2024-05-21 21:20:10 +08:00
Sun Yimin
5c4b252795
kdf-sm3: rollback 2024-05-21 17:50:10 +08:00
Sun Yimin
41c2a3e6e5
kdf-sm3: arm64 try another address model 2024-05-21 17:47:56 +08:00
Sun Yimin
7c832f65e7
kdf-sm3: optimize arm64 2024-05-21 17:38:04 +08:00
Sun Yimin
a81432fbf8
kdf-sm3: fix arm64 2024-05-21 16:09:29 +08:00
Sun Yimin
d248784491
kdf-sm3: fix arm64 bug 2024-05-21 16:02:58 +08:00
Sun Yimin
53cd7522a0
kdf-sm3: fix buffer length issue 2024-05-21 15:46:59 +08:00
Sun Yimin
dc23026764
kdf-sm3: fix arm64 bug 2024-05-21 15:36:19 +08:00
Sun Yimin
145eba63cb
debug arm64 2024-05-21 15:28:48 +08:00
Sun Yimin
4700112905
debug arm64 2024-05-21 15:10:41 +08:00
Sun Yimin
1ff1d53bed
kdf-sm3: debug arm64 2024-05-21 15:06:46 +08:00
Sun Yimin
79af12761c
kdf-sm3: arm64 debug 2024-05-21 14:42:46 +08:00
Sun Yimin
0ab5fb5baa
kdf-sm3: debug words 2024-05-21 14:17:16 +08:00
Sun Yimin
baa098db08
kdf-sm3: fix arm64 compile error 2024-05-21 11:36:49 +08:00
Sun Yimin
378c2d7d07
kdf-sm3: fix arm64 compile error 2024-05-21 10:27:46 +08:00
Sun Yimin
c581cfa88b
kdf-sm3: fix arm64 compile error 2024-05-21 10:19:02 +08:00
Sun Yimin
866d1bb8d3
kdf-sm3: fix arm64 compile error 2024-05-21 10:13:04 +08:00
Sun Yimin
a276af8f57
kdf-sm3: fix arm64 compile error 2024-05-21 10:10:23 +08:00
Sun Yimin
ab2bc3d819
kdf-sm3: fix arm64 compile issue 2024-05-21 10:03:47 +08:00
Sun Yimin
97d28520b1
kdf-sm3: mult by 4 #221 2024-05-21 09:58:38 +08:00
Sun Yimin
9ef3fdc7d5
kdf: refactoring, create one interface 2024-05-17 08:40:27 +08:00
Sun Yimin
7fb729f4a8
sm2: refine BenchmarkEncrypt test 2024-05-15 10:17:15 +08:00
Sun Yimin
105331f164
sm3: kdf, reduce memory allocation times #220 2024-05-15 09:36:38 +08:00
Sun Yimin
4fe8d28d31
kdf: share Z hash state #220 2024-05-15 08:29:37 +08:00
Sun Yimin
c99ad27ce1
kdf: share Z hash state #220 2024-05-15 08:28:47 +08:00
Sun Yimin
57318eaf5b
x509: include OID in duplicate extension error message 2024-05-08 14:35:20 +08:00
Sun Yimin
580f71f23a
Merge pull request #218 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.23.0
build(deps): bump golang.org/x/crypto from 0.22.0 to 0.23.0
2024-05-07 07:52:21 +08:00
dependabot[bot]
a91b6cbaae
build(deps): bump golang.org/x/crypto from 0.22.0 to 0.23.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.22.0 to 0.23.0.
- [Commits](https://github.com/golang/crypto/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 23:46:31 +00:00
Sun Yimin
e8b30cd331
adjust README 2024-04-12 08:16:22 +08:00
Sun Yimin
e185301cfb
Merge pull request #217 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.22.0
build(deps): bump golang.org/x/crypto from 0.21.0 to 0.22.0
2024-04-09 07:17:09 +08:00
dependabot[bot]
b032e5cc03
build(deps): bump golang.org/x/crypto from 0.21.0 to 0.22.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.21.0 to 0.22.0.
- [Commits](https://github.com/golang/crypto/compare/v0.21.0...v0.22.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 23:15:12 +00:00
Sun Yimin
1cc2250496
Merge pull request #216 from emmansun/dependabot/go_modules/golang.org/x/sys-0.19.0
build(deps): bump golang.org/x/sys from 0.18.0 to 0.19.0
2024-04-09 07:14:27 +08:00
dependabot[bot]
75ba5115f8
build(deps): bump golang.org/x/sys from 0.18.0 to 0.19.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.18.0 to 0.19.0.
- [Commits](https://github.com/golang/sys/compare/v0.18.0...v0.19.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 23:12:50 +00:00
Sun Yimin
fcdcb07c93
internal/subtle: remove PCALIGN first 2024-04-01 08:57:18 +08:00
Sun Yimin
ef0d1a2fe0
internal/subtle: optimize amd64 2024-04-01 08:53:21 +08:00
Sun Yimin
df85a7f623
internal: align build flag 2024-03-29 17:55:57 +08:00
Sun Yimin
db87b0556f
ci: enable race detector 2024-03-29 14:37:58 +08:00
Sun Yimin
02258d2351
sm4: reduce slice checking internally 2024-03-27 13:08:27 +08:00
Sun Yimin
34dd5104ee
sm4: reduce slice checking internally 2024-03-27 09:36:56 +08:00
Sun Yimin
e4909bed2d
sm4: reduce allocations 2024-03-27 08:38:25 +08:00
Sun Yimin
178241aa0f
avoid legacy 32 bit system compile error 2024-03-07 17:35:48 +08:00
Sun Yimin
8b70f00b38
internal/cpuid: fix arm64 darwin build 2024-03-06 22:16:53 +08:00
Sun Yimin
b07fac3d82
Update macos.yml 2024-03-06 21:24:42 +08:00
Sun Yimin
7fee50dfe9
update ppc64le ci 2024-03-06 17:50:15 +08:00
Sun Yimin
5c85d63724
internal/bigmod: unroll loop in addMulVVW for ppc64x 2024-03-06 17:47:29 +08:00
Sun Yimin
88ddf3e3d2
smx509: avoid Android root store paths on other Linuxes 2024-03-06 17:36:12 +08:00
Sun Yimin
66c05083bf
smx509: implement SetFallbackRoots #211 2024-03-06 13:02:56 +08:00
Sun Yimin
3a2c7e2c9b
smx509: [sync sdk] crypto/x509: implement AddCertWithConstraint #208 2024-03-06 08:35:14 +08:00
Sun Yimin
5adc912824
refine build tags 2024-03-05 09:47:49 +08:00
Sun Yimin
df3166f032
Merge pull request #207 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.21.0
build(deps): bump golang.org/x/crypto from 0.20.0 to 0.21.0
2024-03-05 07:58:46 +08:00
dependabot[bot]
dc4ff244f1
build(deps): bump golang.org/x/crypto from 0.20.0 to 0.21.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.20.0 to 0.21.0.
- [Commits](https://github.com/golang/crypto/compare/v0.20.0...v0.21.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-04 23:56:01 +00:00
Sun Yimin
b5bddf37d0
Merge pull request #206 from emmansun/dependabot/go_modules/golang.org/x/sys-0.18.0
build(deps): bump golang.org/x/sys from 0.17.0 to 0.18.0
2024-03-05 07:55:28 +08:00
dependabot[bot]
84978b2c70
build(deps): bump golang.org/x/sys from 0.17.0 to 0.18.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.17.0 to 0.18.0.
- [Commits](https://github.com/golang/sys/compare/v0.17.0...v0.18.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-04 23:53:17 +00:00
Sun Yimin
48589f0876
internal/sm2ec: amd64, optimize select SIMD 2024-03-04 17:50:35 +08:00
Sun Yimin
f7beee3dae
internal/bigmod: riscv64, try old version 2024-03-04 11:15:47 +08:00
Sun Yimin
140e738f80
ci: fixit 2024-03-04 11:04:36 +08:00
Sun Yimin
5722fdbdc8
ci: riscv64+1.22 2024-03-04 11:02:47 +08:00
Sun Yimin
2b95e2808c
ci: build riscv64 2024-03-04 10:12:26 +08:00
Sun Yimin
45b41b9596
limist the test scope 2024-03-04 09:52:36 +08:00
Sun Yimin
a37c441993
internal/bigmod: test riscv64 2024-03-04 09:26:57 +08:00
Sun Yimin
5ca8006d1e
internal/bigmod: port riscv64 implementation from Golang 2024-03-04 08:53:33 +08:00
Sun Yimin
b3b9cb22a2
ci: rename 2024-03-04 08:35:05 +08:00
Sun Yimin
64fe377c25
ci: add riscv64 2024-03-04 08:34:15 +08:00
Sun Yimin
9f7e3ef018
internal/sm2ec: supplement comments 2024-03-01 17:40:15 +08:00
Sun Yimin
53ac591635
internal/sm2ec: amd64 refactoring, reduce duplicated code 2024-02-29 17:53:28 +08:00
Sun Yimin
fabcb6ad30
internal/sm2ec: amd64, optimize point double 2024-02-28 17:39:27 +08:00
Sun Yimin
ee7af1bda3
internal/sm2ec: use ADX for mul/sqr and internal sqr 2024-02-27 17:44:30 +08:00
Sun Yimin
51fc24c704
Merge pull request #205 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.20.0
build(deps): bump golang.org/x/crypto from 0.19.0 to 0.20.0
2024-02-27 07:08:00 +08:00
dependabot[bot]
bf38c0e462
build(deps): bump golang.org/x/crypto from 0.19.0 to 0.20.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.19.0 to 0.20.0.
- [Commits](https://github.com/golang/crypto/compare/v0.19.0...v0.20.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-26 23:03:18 +00:00
Sun Yimin
18cc283af2
internal/sm2ec: add comments 2024-02-26 08:25:37 +08:00
emmansun
35466446d4 internal/sm2ec: order sqr/mul WWMM sub first 2024-02-24 13:36:46 +08:00
Sun Yimin
0996508b5b
internal/sm2ec: use ADCX/ADOX for order WWMM mul/sqr 2024-02-23 17:35:19 +08:00
Sun Yimin
052040fd82
internal/sm2ec: mul WWMM reduction, sub first 2024-02-22 17:44:16 +08:00
Sun Yimin
2553456216
internal/sm2ec: update WWMM reduction for Square 2024-02-22 14:53:02 +08:00
Sun Yimin
de2376fe60
Merge pull request #203 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.19.0
build(deps): bump golang.org/x/crypto from 0.18.0 to 0.19.0
2024-02-13 08:07:08 +08:00
dependabot[bot]
5b4c0424d5
build(deps): bump golang.org/x/crypto from 0.18.0 to 0.19.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.18.0 to 0.19.0.
- [Commits](https://github.com/golang/crypto/compare/v0.18.0...v0.19.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-12 23:05:46 +00:00
Sun Yimin
6c25107cd1
ci: add go1.22 2024-02-07 16:51:47 +08:00
Sun Yimin
78c7cf81fe
ciphter/ctr: remove uselss import 2024-02-07 13:44:33 +08:00
Sun Yimin
267ff02783
cipher/ctr: add more test data 2024-02-07 13:41:52 +08:00
Sun Yimin
6b808a6003
zuc: refactor S1_compute on arm64 2024-01-31 17:36:28 +08:00
Sun Yimin
a2ce3f51d0
sm4: reduce bounds check 2024-01-31 14:48:46 +08:00
Sun Yimin
056d14a892
ci: rollback 2024-01-31 13:19:48 +08:00
Sun Yimin
1f3d5d19a4
ci: support go 1.22 2024-01-31 13:16:29 +08:00
Sun Yimin
19636d09c1
sm4: code refactor for block 2024-01-31 13:08:51 +08:00
Sun Yimin
aaabb09dac
sm2: saving some temporary variables 2024-01-30 17:51:13 +08:00
Sun Yimin
fe4e699b19
zuc: optimize constant loading on arm64 2024-01-30 17:33:34 +08:00
Sun Yimin
9a45c4101b
sm4: optimize constant value loading on arm64 2024-01-30 13:10:41 +08:00
Sun Yimin
515cabfd04
sm4: optimize constant loading on arm64 2024-01-30 13:04:03 +08:00
Sun Yimin
d9591cf102
fix action 2024-01-25 17:49:40 +08:00
Sun Yimin
f04d7f102f
add FORCE_SM4BLOCK_AESNI test 2024-01-25 17:47:25 +08:00
Sun Yimin
a01428eaf3
sm4: add env var FORCE_SM4BLOCK_AESNI & give up cbc asm implementation 2024-01-25 17:46:09 +08:00
Sun Yimin
29b6da1d37
sm4: change to use pure go for single block encryption/decryption 2024-01-25 09:02:28 +08:00
Sun Yimin
8e6f9c8fb4
fix macos action 2024-01-24 13:16:41 +08:00
Sun Yimin
8198f2aa8e
fix darwin cpu feature detect issue 2024-01-24 13:11:09 +08:00
Sun Yimin
5cf5e347bc
internal/bigmod: sync sdk #200 2024-01-12 17:43:51 +08:00
Sun Yimin
25ead7dc1f
smx509: refactor p8 parse and pkix public key parse 2024-01-11 17:45:55 +08:00
Sun Yimin
7db8067549
smx509: can parse openssl v3.1.3 p8 sm2 private key #197 2024-01-09 08:29:18 +08:00
Sun Yimin
192bcb95bd
Merge pull request #199 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.18.0
build(deps): bump golang.org/x/crypto from 0.17.0 to 0.18.0
2024-01-09 07:42:12 +08:00
dependabot[bot]
9383525118
build(deps): bump golang.org/x/crypto from 0.17.0 to 0.18.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.17.0 to 0.18.0.
- [Commits](https://github.com/golang/crypto/compare/v0.17.0...v0.18.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-08 23:25:23 +00:00
Sun Yimin
906f7d4891
Merge pull request #198 from emmansun/dependabot/go_modules/golang.org/x/sys-0.16.0
build(deps): bump golang.org/x/sys from 0.15.0 to 0.16.0
2024-01-09 07:24:20 +08:00
dependabot[bot]
49440cb3ce
build(deps): bump golang.org/x/sys from 0.15.0 to 0.16.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.15.0 to 0.16.0.
- [Commits](https://github.com/golang/sys/compare/v0.15.0...v0.16.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-08 23:19:03 +00:00
Sun Yimin
ceff9bfd19
doc: sm4 AEAD mode dst explanation 2023-12-29 17:57:40 +08:00
Sun Yimin
f9b884b62c
README 增加软件许可 2023-12-26 08:31:50 +08:00
Sun Yimin
93f3a5e020
doc: update sm2/sm4 document 2023-12-22 17:54:42 +08:00
Sun Yimin
3ac62049d6
doc: SM9标识密码算法应用指南 2023-12-19 10:36:06 +08:00
Sun Yimin
96c42cd00a
Merge pull request #192 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.17.0
build(deps): bump golang.org/x/crypto from 0.16.0 to 0.17.0
2023-12-19 07:45:50 +08:00
dependabot[bot]
3bf75613d2
build(deps): bump golang.org/x/crypto from 0.16.0 to 0.17.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.16.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.16.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-18 23:36:14 +00:00
Sun Yimin
c1f84cefed
sm2: naming convention 2023-12-18 08:17:10 +08:00
Sun Yimin
c6cc18ee9c
doc: sm2 update examples 2023-12-18 07:58:52 +08:00
Sun Yimin
77b581e409
doc: Errata 2023-12-15 18:04:06 +08:00
Sun Yimin
5740fe0e1c
add back private key print with %q 2023-12-15 17:47:32 +08:00
Sun Yimin
515aa31259
sm2: add comments and refactor 2023-12-15 15:11:49 +08:00
Sun Yimin
cad90f95ec
internal/sm2ec: align error message 2023-12-15 13:17:43 +08:00
Sun Yimin
58d30f6655
sm2: fix bug 2023-12-15 13:14:02 +08:00
Sun Yimin
167f0e0b11
sm2: #189, #190, #191 2023-12-15 13:06:53 +08:00
Sun Yimin
aa4e023972
Update document 2023-12-14 16:28:25 +08:00
Sun Yimin
0dfbe032fb
fix link issue 2023-12-14 11:08:00 +08:00
Sun Yimin
a3c46ce202
update english disclaimer 2023-12-14 11:06:43 +08:00
Sun Yimin
68247bc044
README deault to Chinese 2023-12-14 10:42:31 +08:00
Sun Yimin
6bc061a549
cipher: reduce duplicate code 2023-12-13 14:19:31 +08:00
Sun Yimin
0f3d76705b
sm2: fix enveloped key issue #188 2023-12-13 13:43:05 +08:00
Sun Yimin
fefb280170
doc: 重新编排 2023-12-13 08:02:22 +08:00
Sun Yimin
2187bea0d9
doc: 增加与KMS集成这一节及其它 2023-12-12 17:32:48 +08:00
Sun Yimin
015ca1b6b2
doc: fix markdown display 2023-12-12 13:07:10 +08:00
Sun Yimin
e2c135b9b9
doc: fix display 2023-12-12 13:00:46 +08:00
Sun Yimin
97ddcab4b2
doc: sm3/sm4应用指南 2023-12-12 11:51:34 +08:00
Sun Yimin
880691746d
sm2: makes CalculateSM2Hash public 2023-12-12 08:12:28 +08:00
Sun Yimin
44336ac775
增加与KMS集成一节 2023-12-11 21:11:08 +08:00
Sun Yimin
52e02c209b
doc: fix github page display issue 2023-12-11 17:46:07 +08:00
Sun Yimin
097d98eb7d
doc: SM2椭圆曲线公钥密码算法应用指南 2023-12-11 17:38:58 +08:00
Sun Yimin
ec51f8827d
fix ut 2023-12-08 17:58:15 +08:00
Sun Yimin
c913b7d304
align error message pattern 2023-12-08 17:55:29 +08:00
Sun Yimin
82125c00a4
cipher: align error message pattern 2023-12-08 17:42:16 +08:00
Sun Yimin
3c11e3a166
Update README 2023-12-07 08:09:42 +08:00
Sun Yimin
9384d1f1ac
Update README-CN 2023-12-06 16:07:53 +08:00
Sun Yimin
ee397cdbd7
cipher: add SM legacy operation modes 2023-12-06 14:45:08 +08:00
Sun Yimin
67c80c82b4
cipher/hctr: eliminate bounds checks in the loop 2023-12-06 10:24:22 +08:00
emmansun
8213fb98c5 cipher/hctr: add comments for hctrReductionTable 2023-12-04 11:24:32 +08:00
emmansun
22358080d5 cipher/hctr: correct comments 2023-12-04 10:50:13 +08:00
emmansun
e8f39ed529 update LengthPreservingMode interface 2023-12-04 10:27:26 +08:00
emmansun
e5effb8bb9 cipher/hctr: optimization with GCM GF128 method 2023-12-03 10:25:44 +08:00
Sun Yimin
9d467f8051
cipher: hctr POC 2023-12-01 15:51:15 +08:00
Sun Yimin
68372f62c4
add package description for padding 2023-11-28 18:05:31 +08:00
Sun Yimin
69a480021a
Merge pull request #185 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.16.0
build(deps): bump golang.org/x/crypto from 0.15.0 to 0.16.0
2023-11-28 08:17:44 +08:00
dependabot[bot]
a0c28edf9d
build(deps): bump golang.org/x/crypto from 0.15.0 to 0.16.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.15.0 to 0.16.0.
- [Commits](https://github.com/golang/crypto/compare/v0.15.0...v0.16.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-28 00:14:10 +00:00
Sun Yimin
e1ed96dfdf
Merge pull request #184 from emmansun/dependabot/go_modules/golang.org/x/sys-0.15.0
build(deps): bump golang.org/x/sys from 0.14.0 to 0.15.0
2023-11-28 08:13:23 +08:00
dependabot[bot]
cc44a1a90a
build(deps): bump golang.org/x/sys from 0.14.0 to 0.15.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.14.0 to 0.15.0.
- [Commits](https://github.com/golang/sys/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-27 23:53:46 +00:00
Sun Yimin
e373ac7968
zuc: arm64, eia256 uses VMOVQ & VTBL 2023-11-09 15:28:49 +08:00
Sun Yimin
632edd80d5
zuc: arm64, eia256 try VMOVQ to load const 2023-11-09 14:57:20 +08:00
Sun Yimin
b8cfff88b4
ZUC: arm64, EIA uses VDUP to reduce VMOV 2023-11-09 14:42:22 +08:00
Sun Yimin
3d299a6480
x509: optimize the performance of checkSignature #181 2023-11-09 13:03:18 +08:00
Sun Yimin
e8bbfaa5b7
remove travis ci and trigger sm3/4 ni CI 2023-11-09 11:17:05 +08:00
Sun Yimin
b1b7095ce9
zuc: arm64, typo 2023-11-09 10:38:03 +08:00
Sun Yimin
851d02b3ea
Change VMOV to VDUP #179 2023-11-09 10:31:08 +08:00
Sun Yimin
4f511e2125
internal/subtle xor 简化代码,去除重复 #75 2023-11-09 09:32:10 +08:00
Sun Yimin
1b200746af
fix bug #74 2023-11-09 08:50:13 +08:00
Sun Yimin
80a79dacc5
fix bug #74 2023-11-09 08:46:44 +08:00
Sun Yimin
83cf55a137
sm2p256_asm.go中切片直接转数组指针 #74 2023-11-09 08:44:50 +08:00
Sun Yimin
17a3dd8d4b
change interface{} to any, and remove "+build" build tag #77 2023-11-09 08:34:50 +08:00
Sun Yimin
79765c757f
upgrade go to 1.18 #178 2023-11-09 08:17:49 +08:00
Sun Yimin
334520e4f8
upgrade go to 1.18 #178 2023-11-09 08:15:55 +08:00
Sun Yimin
af434c5425
try again 2023-11-08 14:48:01 +08:00
Sun Yimin
7618dbe006
rollback 2023-11-08 14:21:39 +08:00
Sun Yimin
d8c22330e3
change address mode 2023-11-08 14:14:26 +08:00
Sun Yimin
d411f13a58
internal/sm2ec: try to fix compile error 2023-11-08 14:05:58 +08:00
Sun Yimin
795152631d
internal/sm2ec: arm64, uses new method to load y2 2023-11-08 14:00:07 +08:00
Sun Yimin
84045dc25f
zuc: arm64, uses new method to load global data 2023-11-08 13:43:56 +08:00
Sun Yimin
80e88ea2b2
sm4: use new method to load global data 2023-11-08 13:23:04 +08:00
Sun Yimin
c256f1d257
test load global data method 2023-11-08 13:06:34 +08:00
Sun Yimin
230fea3435
internal/sm2ec: reduce memory access 2023-11-08 10:26:19 +08:00
Sun Yimin
720630b65d
internal/sm2ec: fix compile error 2023-11-08 09:46:26 +08:00
Sun Yimin
f68cfb7759
intenal/sm2ec: fix typo 2023-11-08 09:42:18 +08:00
Sun Yimin
14c9c94894
internal/sm2ec: fix typo 2023-11-08 09:38:28 +08:00
Sun Yimin
93a5d6abd1
internal/sm2ec: uses neon inst. for p256PointAddAffineAsm 2023-11-08 09:32:31 +08:00
Sun Yimin
2f60f0062b
internal/sm2ec: use neon inst. for p256Select 2023-11-07 16:34:58 +08:00
Sun Yimin
b5c593005d
internal/sm2ec: uses neon inst. for p256SelectAffine 2023-11-07 16:11:05 +08:00
Sun Yimin
ef55df3657
sm9/bn256: use neon inst. for conditional move 2023-11-07 15:33:52 +08:00
Sun Yimin
06a310dd4d
internal/sm2ec: use neon inst. for p256MovCond 2023-11-07 15:05:49 +08:00
Sun Yimin
39751be045
internal/sm2ec: fix bug 2023-11-07 08:59:50 +08:00
Sun Yimin
224c41c0d0
internal/sm2ec: use neon for p256BigToLittle 2023-11-07 08:54:30 +08:00
Sun Yimin
6535a2d27f
Merge pull request #177 from emmansun/revert-176-dependabot/go_modules/golang.org/x/sys-0.14.0
Revert "build(deps): bump golang.org/x/sys from 0.13.0 to 0.14.0"
2023-11-07 08:05:03 +08:00
Sun Yimin
846049f855
Revert "build(deps): bump golang.org/x/sys from 0.13.0 to 0.14.0" 2023-11-07 08:04:53 +08:00
Sun Yimin
0c9228e6b4
Merge pull request #176 from emmansun/dependabot/go_modules/golang.org/x/sys-0.14.0
build(deps): bump golang.org/x/sys from 0.13.0 to 0.14.0
2023-11-07 07:08:13 +08:00
dependabot[bot]
9668d1a38b
build(deps): bump golang.org/x/sys from 0.13.0 to 0.14.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.13.0 to 0.14.0.
- [Commits](https://github.com/golang/sys/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-06 23:06:41 +00:00
Sun Yimin
8f5e603f94
sm4: disable PXOR use m128 directly 2023-11-01 15:00:49 +08:00
Sun Yimin
2f163662b5
sm4: cbc enc, do not mem directly 2023-11-01 13:03:46 +08:00
Sun Yimin
319d794ef2
update readme for xts mode 2023-10-25 08:57:21 +08:00
Sun Yimin
2bc8260bcb
upgrade ci 2023-10-24 16:54:00 +08:00
Sun Yimin
55e8c795e5
sm9/bn256: fix arm64 non-avx2 issue 2023-10-24 14:50:51 +08:00
Sun Yimin
5243d0fe91
sm4: code format 2023-10-18 08:07:19 +08:00
Sun Yimin
9bd64f94d3
Merge pull request #170 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.14.0
build(deps): bump golang.org/x/crypto from 0.13.0 to 0.14.0
2023-10-10 11:03:47 +08:00
dependabot[bot]
d6fcbcc7d2
build(deps): bump golang.org/x/crypto from 0.13.0 to 0.14.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.13.0 to 0.14.0.
- [Commits](https://github.com/golang/crypto/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-09 23:32:21 +00:00
emmansun
400147ed3c zuc: eea, fix can't src/dst can't use same buffer issue #169 2023-09-29 09:57:27 +08:00
Sun Yimin
5b3dfb6fa7
sm4: amd64, reduce VBROADCASTI128 usage 2023-09-28 13:19:52 +08:00
Sun Yimin
15d1b57a23
Update asm_arm64.s 2023-09-28 12:04:45 +08:00
Sun Yimin
87041f3ad3
sm4: arm64 load const issue 2023-09-28 11:54:24 +08:00
Sun Yimin
218ce35c71
sm4: arm64, fix load const issue 2023-09-28 11:47:38 +08:00
Sun Yimin
eba2b736bd
sm4: arm64, simplify const loading 2023-09-28 11:44:48 +08:00
Sun Yimin
53e121c2b5
sm4: optimize TAO L1 #168 2023-09-28 10:11:31 +08:00
Sun Yimin
cc441bed27
加入中文README 2023-09-27 17:32:22 +08:00
Sun Yimin
9a4cb2c34f
sm4: use POR, although it does not affect the correctness 2023-09-27 09:22:22 +08:00
Sun Yimin
232af559d7
sm3: 使用GG2等价公式 #166 2023-09-22 17:09:55 +08:00
Sun Yimin
f2199843b1
kdf: add benchmark test 2023-09-21 13:48:51 +08:00
Sun Yimin
edcba25490
sm3: refactoring 2023-09-20 15:43:32 +08:00
Sun Yimin
76bafca3c4
sm3: format code, #165 2023-09-20 10:27:01 +08:00
Sun Yimin
125b272c88
sm3: amd64 sse version #165 2023-09-20 10:07:46 +08:00
Sun Yimin
077664e809
sm3: amd64, avx version, remove usage of RORX #157 2023-09-19 17:32:53 +08:00
Sun Yimin
cee7547606
sm3: refactoring asm, extract constants 2023-09-19 16:53:42 +08:00
Sun Yimin
df3a5c10de
sm3: amd64, optimize message schedule #164 2023-09-19 10:33:17 +08:00
Sun Yimin
b75f5d1e74
sm3: arm64, message schedule #164 2023-09-18 17:35:31 +08:00
Sun Yimin
6b805f9824
sm3: amd64, optimize message schedule #164 2023-09-18 17:06:46 +08:00
Sun Yimin
d56b3d1ed0
sm3: arm64, do not use local storage #162 2023-09-18 08:21:32 +08:00
Sun Yimin
77893f07f4
sm3: optimize FF2, #163 2023-09-15 16:01:00 +08:00
Sun Yimin
c5d44ca9b2
sm3: reduce memory usage, #162 2023-09-15 13:54:12 +08:00
Sun Yimin
5403b003fa
sm3: use ANDNL #160 2023-09-15 11:51:02 +08:00
Sun Yimin
0056f1aa7b
recover arm64 ci 2023-09-14 16:57:17 +08:00
Sun Yimin
2dbf59e90f
sm3: arm64, code interleaving #159 2023-09-14 16:54:12 +08:00
Sun Yimin
1d204e87e1
sm3: try it #159 2023-09-14 16:33:02 +08:00
Sun Yimin
87282640e8
sm3: arm64, fix copy paste issue #159 2023-09-14 16:13:51 +08:00
Sun Yimin
f7a6674a93
sm3: arm64, fix #159 2023-09-14 15:59:05 +08:00
Sun Yimin
4e98900127
sm3: arm64, fix #159 2023-09-14 15:44:19 +08:00
Sun Yimin
d5a239b5d6
sm3: arm64 neon test #159 2023-09-14 15:39:23 +08:00
Sun Yimin
c35269f866
sm3: amd64 avx support, #157 2023-09-13 17:33:49 +08:00
Sun Yimin
aa5ff27e5e
sm3: arm64, try BIC instruction 2023-09-13 17:29:32 +08:00
Sun Yimin
d46ef92f74
sm3: amd64 asm, RORXL uses postive value 2023-09-12 15:34:51 +08:00
Sun Yimin
5e08c8e49b
sm3: amd64 asm, reduce duplicated code 2023-09-12 11:13:55 +08:00
Sun Yimin
ee35aa68ba
smx509: add example test case for reference #155 2023-09-12 08:44:56 +08:00
Sun Yimin
43c77c4705
Merge pull request #156 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.13.0
build(deps): bump golang.org/x/crypto from 0.12.0 to 0.13.0
2023-09-12 08:24:44 +08:00
dependabot[bot]
10a2e9763e
build(deps): bump golang.org/x/crypto from 0.12.0 to 0.13.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.12.0 to 0.13.0.
- [Commits](https://github.com/golang/crypto/compare/v0.12.0...v0.13.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-11 23:59:27 +00:00
Sun Yimin
cd4d5581c1
sm3: add more test vectors 2023-09-11 17:20:02 +08:00
Sun Yimin
6cd67b155c
sm3: amd64, use VPSHUFB for byte level rotate left shift 2023-09-11 16:43:16 +08:00
Sun Yimin
e811c959ab
sm3: arm64 align format 2023-09-11 13:56:11 +08:00
Sun Yimin
150f1bdb28
sm3: amd64, reduce MOVL 2023-09-11 10:59:59 +08:00
Sun Yimin
429c2db8aa
plugin: sm2 sm9 use BP carefully 2023-09-11 08:47:02 +08:00
Sun Yimin
719bca92db
sm3: amd64 asm, align format 2023-09-11 08:28:47 +08:00
Sun Yimin
3bb540d45f
sm9/bn256: amd64 asm support plugin, eliminate usage of R15 #154 2023-09-08 16:36:43 +08:00
Sun Yimin
0d577d3f42
internal/sm2ec: fix error 2023-09-08 14:09:48 +08:00
Sun Yimin
7152f4d1ac
internal/sm2ec: amd64 support plugin(eliminate usage of R15) #154 2023-09-08 14:09:16 +08:00
Sun Yimin
30acaf4dd6
sm3: amd64 eliminate usage of R15 2023-09-07 17:42:55 +08:00
Sun Yimin
df14178097
zuc: amd64 eliminate the usage of R15 2023-09-07 16:32:08 +08:00
Sun Yimin
17e66c88d8
zuc: arm64 eliminate the usage of R15 2023-09-07 16:27:58 +08:00
Sun Yimin
6ba199a0b7
ci: test plugin build flag #154 2023-09-07 08:56:22 +08:00
Sun Yimin
72019cf860
fix build issue 2023-09-07 08:51:53 +08:00
Sun Yimin
58121ac8cc
build: support plugin flag for amd64 #154 2023-09-07 08:50:10 +08:00
Sun Yimin
dffaf4fcad
zuc: amd64 update comments 2023-09-06 08:16:38 +08:00
Sun Yimin
5301412e48
zuc: fix mistake 2023-09-05 17:42:03 +08:00
Sun Yimin
4423ede309
zuc: add comments 2023-09-05 17:25:31 +08:00
Sun Yimin
5a85197445
Merge pull request #153 from emmansun/dependabot/go_modules/golang.org/x/sys-0.12.0
build(deps): bump golang.org/x/sys from 0.11.0 to 0.12.0
2023-09-05 07:51:29 +08:00
dependabot[bot]
a8f2fd8b2a
build(deps): bump golang.org/x/sys from 0.11.0 to 0.12.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.11.0 to 0.12.0.
- [Commits](https://github.com/golang/sys/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 23:30:08 +00:00
Sun Yimin
75b153887e
sm4: gcm amd64, remove uselss code 2023-09-04 08:36:03 +08:00
Sun Yimin
4f1b16d9c1
Update Acknowledgements 2023-08-28 16:14:55 +08:00
Sun Yimin
e883a00f29
add Acknowledgements 2023-08-28 15:48:23 +08:00
Sun Yimin
8d5c6c4601
sm4: gcm amd64 optmization 2023-08-28 14:41:15 +08:00
emmansun
3f602061fc sm4: gcm amd64 reduce byte shuffling #152 2023-08-26 10:11:25 +08:00
Sun Yimin
d3c19c171a
sm4: xts sm4ni arm64, fix register confliction #151 2023-08-25 13:53:27 +08:00
Sun Yimin
d28883e2c7
sm4: xts sm4ni arm64, fix bug 2023-08-25 13:40:07 +08:00
Sun Yimin
9cc53170df
sm4: remove amd64 build flag 2023-08-25 13:24:11 +08:00
Sun Yimin
8253e1be8e
sm4: xts sm4ni arm64, fix duplicated name issue #151 2023-08-25 13:20:55 +08:00
Sun Yimin
1019226803
sm4: xts sm4ni arm64 #151 2023-08-25 13:13:43 +08:00
Sun Yimin
16c5556655
ci: remove special test 2023-08-24 16:49:09 +08:00
Sun Yimin
e6d27e8bae
sm4: xts asm arm64, fix dead loop bug 2023-08-24 16:42:33 +08:00
Sun Yimin
50ddb5347e
sm4: xts asm arm64 one by one 2023-08-24 16:35:08 +08:00
Sun Yimin
a8714d9782
sm4: xts asm arm64 test one by one 2023-08-24 16:28:43 +08:00
Sun Yimin
28a6939861
sm4: xts asm arm64 test 2023-08-24 16:22:38 +08:00
Sun Yimin
6d6339f06d
sm4: xts asm arm64 test 2023-08-24 16:14:58 +08:00
Sun Yimin
3a304ee8dd
sm4: xts asm arm64 test one func first 2023-08-24 16:07:37 +08:00
Sun Yimin
4fc2acf95c
rollback 2023-08-24 15:32:27 +08:00
Sun Yimin
25384f061c
check compile first 2023-08-24 15:20:13 +08:00
Sun Yimin
a3daf1f525
sm4: xts asm arm64 test 2023-08-24 15:03:14 +08:00
Sun Yimin
9ee8ee4529
sm4: xts asm amd64 2023-08-24 11:47:06 +08:00
Sun Yimin
61e5507c69
cipher/xts: arm64, similar like VDUP 2023-08-24 11:24:10 +08:00
Sun Yimin
c8b400a16c
cipher/xts: fix buffer overlap issue 2023-08-23 08:30:40 +08:00
Sun Yimin
099ebd7d92
cipher: add more xts benchmark test 2023-08-22 17:39:51 +08:00
Sun Yimin
76635c4cf3
cipher: xts asm, add random test 2023-08-21 11:07:42 +08:00
Sun Yimin
abbe36143c
cipher: xts arm64, fix compile error 2023-08-21 10:25:45 +08:00
Sun Yimin
de8c35e0f1
cipher: xts arm64 2023-08-21 10:22:46 +08:00
Sun Yimin
bf355a1ea3
cipher: xts amd64 reduce inst. 2023-08-20 12:46:41 +08:00
emmansun
ddea8332fe cipher: optimize gb gf(2^128) reduction 2023-08-20 12:05:48 +08:00
Sun Yimin
4eacdccbf6
cipher: implement double tweak amd64 asm #149 2023-08-18 17:49:57 +08:00
Sun Yimin
0eaad02df4
cipher: refactor xts mode #149 2023-08-17 12:49:28 +08:00
Sun Yimin
9d6e46cafd
cipher: refactor xts mode #149 2023-08-17 12:48:53 +08:00
emmansun
71ab69ef9b internal/bigmod: avoid duplicated name with golang sdk 2023-08-16 14:34:31 +08:00
emmansun
d4c92f1b17 test golang 1.21 2023-08-16 14:21:01 +08:00
Sun Yimin
6478a408e6
padding: ISO/IEC 9797 method 2 2023-08-08 17:35:16 +08:00
Sun Yimin
33d9dc7db7
cipher: xts, update function name 2023-08-08 17:31:55 +08:00
Sun Yimin
f9bd2f002a
cipher: xts supports GB/T 17964-2021 2023-08-08 17:26:08 +08:00
Sun Yimin
feb76edda8
sm4: fix cbc iv issue 2023-08-08 13:07:10 +08:00
Sun Yimin
0fbc30f868
sm4: optimize cbc iv handling 2023-08-08 12:35:42 +08:00
Sun Yimin
cb47e82478
sm4: fix arm64 copy paste issue 2023-08-08 08:29:07 +08:00
Sun Yimin
29d7b25b95
sm4: cbc ecb asm rename 2023-08-08 08:22:17 +08:00
Sun Yimin
faeea141d7
Merge pull request #148 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.12.0
build(deps): bump golang.org/x/crypto from 0.11.0 to 0.12.0
2023-08-08 07:23:00 +08:00
dependabot[bot]
48cecae533
build(deps): bump golang.org/x/crypto from 0.11.0 to 0.12.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.11.0 to 0.12.0.
- [Commits](https://github.com/golang/crypto/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-07 23:16:54 +00:00
Sun Yimin
682a48eb6e
Merge pull request #147 from emmansun/dependabot/go_modules/golang.org/x/sys-0.11.0
build(deps): bump golang.org/x/sys from 0.10.0 to 0.11.0
2023-08-08 07:16:16 +08:00
dependabot[bot]
8e52dbde96
build(deps): bump golang.org/x/sys from 0.10.0 to 0.11.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.10.0 to 0.11.0.
- [Commits](https://github.com/golang/sys/compare/v0.10.0...v0.11.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-07 23:12:22 +00:00
Sun Yimin
20ab2874fa
Update cbc_cipher_asm_arm64.s 2023-08-07 21:55:19 +08:00
Sun Yimin
90f0279cb2
sm4: arm64 fix 2023-08-07 17:10:14 +08:00
Sun Yimin
b65b01a6a4
sm4: arm64 fix 2023-08-07 16:58:13 +08:00
Sun Yimin
c7fc1431ba
sm4: arm64 fix 2023-08-07 16:53:59 +08:00
Sun Yimin
06dbc52e48
sm4: arm64 fix 2023-08-07 16:48:14 +08:00
Sun Yimin
4e50b3dd6b
sm4: cbc ecb mode enhancement 2023-08-07 16:43:29 +08:00
Sun Yimin
e00fbe696d
sm4: optimize avx2 implementation 2023-08-04 15:52:00 +08:00
Sun Yimin
24637cf61d
sm4: add test cases, cover more plaintext length 2023-08-04 08:25:16 +08:00
Sun Yimin
71afa44b91
sm4: fix arm64 cbc 8 blocks decryption issue 2023-08-03 16:40:31 +08:00
Sun Yimin
dba47d3c14
sm4: fix arm64 SM4_8BLOCKS_ROUND issue #146 2023-08-03 16:18:56 +08:00
Sun Yimin
1e360021c4
sm4: fix amd64 avx2 decrypt 4 blocks issue #146 2023-08-03 16:13:05 +08:00
Sun Yimin
4bc3c5d27b
sm4: improve throughput #146 2023-08-03 15:17:01 +08:00
Sun Yimin
fe84641340
sm4: use simple inst. 2023-07-31 17:32:41 +08:00
Sun Yimin
c813a1fb65
internal/sm2ec: add boundary test 2023-07-28 15:26:42 +08:00
Sun Yimin
ca474a67ba
sm9/bn256: remove useless tmp value storage 2023-07-28 11:19:58 +08:00
Sun Yimin
9035a35b64
sm9/bn256: fix arm64 grammatical errors 2023-07-27 16:12:56 +08:00
Sun Yimin
0ee8177079
sm9/bn256: gfp2MulU1 2023-07-27 15:59:52 +08:00
Sun Yimin
e3d14fb41a
sm9/bn256: reduce register move 2023-07-27 13:03:25 +08:00
Sun Yimin
a10e64f6f5
sm9/bn256: add test cases 2023-07-26 16:37:44 +08:00
Sun Yimin
ba6bd136f9
internal/sm2ec: add comment for mont. reduction and others 2023-07-26 10:26:32 +08:00
Sun Yimin
49513c7420
sm9/bn256: gt use cyclo6 squaring 2023-07-25 16:49:44 +08:00
Sun Yimin
ce07f3afc0
Rollback test_qemu.yml 2023-07-25 15:14:58 +08:00
Sun Yimin
4b09d140af
sm9/bn256: arm64 fix add complete issue 2023-07-25 15:11:41 +08:00
Sun Yimin
0a559b5202
sm9/bn256: arm64 complete add 2023-07-25 15:02:41 +08:00
Sun Yimin
db92a6f60e
sm9/bn256: fix arm64 complete double issue 2023-07-25 13:12:45 +08:00
Sun Yimin
1ecdb1a563
sm9/bn256: arm64 curvePointDoubleComplete fix issue 2023-07-25 13:02:19 +08:00
Sun Yimin
628054399a
sm9/bn256: adjust test case order 2023-07-25 11:54:29 +08:00
Sun Yimin
dd5fcd13d6
sm9/bn256: arm64 curvePointDoubleComplete 2023-07-25 11:47:50 +08:00
Sun Yimin
04e6a1c9b3
sm9/bn256: arm64 gfp2Square & gfp2SquareU 2023-07-25 08:35:00 +08:00
Sun Yimin
c62d6daf74
sm9/bn256: arm64 gfp2MulU 2023-07-25 08:21:44 +08:00
Sun Yimin
ecf14648e9
sm9/bn256: arm64 gfp2Mul 2023-07-25 08:14:56 +08:00
Sun Yimin
087b3ae596
sm9/bn256: arm64 test mul, found issue, try again 2023-07-25 08:09:46 +08:00
Sun Yimin
abf506d8ee
sm9/bn256: arm64 test mul 2023-07-25 08:06:07 +08:00
Sun Yimin
a1335db683
sm9/bn256: arm64 test mul 2023-07-25 07:59:23 +08:00
Sun Yimin
ef4277c510
Update test_qemu.yml 2023-07-24 19:47:20 +08:00
Sun Yimin
f6ad6f3719
sm9/bn256: arm64 fix mul issue 2023-07-24 16:26:16 +08:00
Sun Yimin
4985c6da53
sm9/bn256: arm64, use register R27 2023-07-24 15:59:39 +08:00
Sun Yimin
73cc8d737c
sm9/bn256: fix copy paste error 2023-07-24 15:31:11 +08:00
Sun Yimin
b7ff7ecd8a
sm9/bn256: fix compile error 2023-07-24 14:46:10 +08:00
Sun Yimin
7989a62e23
sm9/bn256: arm64, forgot one by one 2023-07-24 14:36:00 +08:00
Sun Yimin
248c2de1ef
sm9/bn256: fix arm64 issue 2023-07-24 14:28:23 +08:00
Sun Yimin
b4bd731996
sm9/bn256: fix arm64 issue 2023-07-24 13:18:08 +08:00
Sun Yimin
2394eea76d
sm9/bn256: fix arm64 issue 2023-07-24 13:13:07 +08:00
Sun Yimin
968dfaafa0
sm9/bn256: gfp2 g1 arm64 method one by one 2023-07-24 13:11:38 +08:00
Sun Yimin
de62767f53
sm9/bn256: addcomplete amd64 2023-07-24 13:02:00 +08:00
emmansun
b21a234037 sm9/bn256: curvePointDoubleComplete asm 2023-07-22 17:29:19 +08:00
emmansun
2d615c7f94 Merge branch 'main' of https://github.com/emmansun/gmsm 2023-07-22 15:32:34 +08:00
Sun Yimin
d452423d62
sm9/bn256: fix gfp triple generic issue 2023-07-21 21:19:45 +08:00
emmansun
a8b10483e1 sm9/bn256: fix gfpTriple generic implementation issue 2023-07-21 21:07:50 +08:00
emmansun
e769cefbd8 Merge branch 'main' of https://github.com/emmansun/gmsm
# Conflicts:
#	sm9/bn256/gfp12_b6.go
2023-07-21 20:43:00 +08:00
Sun Yimin
76131e6438
internal/sm2ec: not use ADX first 2023-07-21 18:06:22 +08:00
Sun Yimin
5b5b26c095
sm9/bn256: fix twist Frobenius bug due to #144, will further review those functions usage 2023-07-21 17:51:25 +08:00
Sun Yimin
16b2a43dc3
sm9/bn256: complete addition fomulas and gfp2 amd64 asm #144 2023-07-21 17:39:06 +08:00
Sun Yimin
a173646017
internal/sm2ec: optiomization for ADX usage and supplement comments 2023-07-20 17:49:53 +08:00
Sun Yimin
bbbf2612bc
sm9/bn256: fix add same bug 2023-07-19 15:26:38 +08:00
Sun Yimin
b9bbf94b47
sm9/bn256: rename special square function name 2023-07-18 17:29:10 +08:00
emmansun
e24d1c34c5 sm9/bn256: use double 2023-07-15 16:25:50 +08:00
Sun Yimin
929e1b892b
sm9/bn256: fix one potential issue 2023-07-14 16:37:00 +08:00
Sun Yimin
fc2f105dd2
sm4: fix AVX version use AVX2 inst. issue 2023-07-13 08:47:05 +08:00
Sun Yimin
fc287b6e96
sm9/bn256: add bilinearity test case 2023-07-12 15:09:25 +08:00
Sun Yimin
9ec8d3bc04
sm9/bn256: add double & triple, fix gfpNeg issue, use Square as possible 2023-07-11 17:30:48 +08:00
Sun Yimin
ba3cbd23c8
Merge pull request #142 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.11.0
build(deps): bump golang.org/x/crypto from 0.10.0 to 0.11.0
2023-07-11 08:26:23 +08:00
dependabot[bot]
c453c21b5f
build(deps): bump golang.org/x/crypto from 0.10.0 to 0.11.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.10.0 to 0.11.0.
- [Commits](https://github.com/golang/crypto/compare/v0.10.0...v0.11.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-11 00:23:56 +00:00
Sun Yimin
c1a20fdb5c
Merge pull request #141 from emmansun/dependabot/go_modules/golang.org/x/sys-0.10.0
build(deps): bump golang.org/x/sys from 0.9.0 to 0.10.0
2023-07-11 08:23:13 +08:00
dependabot[bot]
fd9309fcf4
build(deps): bump golang.org/x/sys from 0.9.0 to 0.10.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.9.0 to 0.10.0.
- [Commits](https://github.com/golang/sys/compare/v0.9.0...v0.10.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-10 23:51:04 +00:00
Sun Yimin
75dc5a6d00
Update README.md 2023-07-09 17:13:19 +08:00
Sun Yimin
29ccad538a
Update README.md 2023-07-08 19:32:26 +08:00
Sun Yimin
9d59be1699
Update README.md 2023-07-08 16:11:29 +08:00
emmansun
cf1b3da289 sm9/bn256: fix purego issue 2023-07-07 20:20:15 +08:00
Sun Yimin
0e54e68bfd
sm9/bn256: asm implementation for gfP Marshal/Unmarshal #140 2023-07-07 18:09:49 +08:00
Sun Yimin
ebe5aca2d8
Update select_generic.go 2023-07-06 17:56:10 +08:00
Sun Yimin
4755d5aa2a
sm9/bn256: also apply to 1-2-6-12 #139 #137 2023-07-06 17:36:34 +08:00
Sun Yimin
5f72151e74
sm9/bn256: special square for final exp & optimize gfp2/gfp12 square #137 #139 2023-07-05 17:58:19 +08:00
Sun Yimin
89f3b0f6d3
sm4: add some comments for asm code 2023-07-05 17:51:26 +08:00
Sun Yimin
8cfd82dc53
sm4: mistake 2023-07-04 10:04:15 +08:00
Sun Yimin
12ef9e0ef9
sm4: optimize amd64 sse, cbc decrypter 2023-07-04 08:38:53 +08:00
emmansun
a53659eb5b sm4: optimize sse version 2023-07-03 16:20:04 +08:00
emmansun
f10b09f5a2 sm4: gcm init use PALIGNR to reduce instructions 2023-07-03 15:41:05 +08:00
Sun Yimin
d3e6412258
sm4: Support AES-NI + AVX #135 2023-07-03 12:00:27 +08:00
emmansun
1e5ba7f5a1 sm9/bn256: add miller benchmark test 2023-07-02 11:46:50 +08:00
emmansun
b493f8cb99 sm9/bn256: avoid value copy #136 2023-07-02 11:23:36 +08:00
Sun Yimin
c7b3d97304
sm9/bn256: value copy acceleration #136 2023-06-30 17:51:35 +08:00
Sun Yimin
78542032f2
bigmod: fix non adx version amd64 256 bits bug #133 2023-06-29 09:52:41 +08:00
Sun Yimin
0afaeb49eb
sm9/bn256: use ADCX ADOX together with MULX #132 2023-06-28 17:38:05 +08:00
Sun Yimin
ce489e2b4b
sm4: fix include order issue 2023-06-28 17:05:38 +08:00
Sun Yimin
39f75ac913
sm4: rename asm macros files 2023-06-28 16:52:40 +08:00
Sun Yimin
7effe0578b
Update ci.yml
add 1.20 ci test
2023-06-28 15:17:40 +08:00
Sun Yimin
1d0e77388a
sm4: ctr mode fix issue and comments 2023-06-27 17:52:23 +08:00
Sun Yimin
8041c5e310
sm2: remove CSPRNG usage 2023-06-27 08:57:31 +08:00
Sun Yimin
c1ea628282
try to reduce ci time 2023-06-27 08:41:01 +08:00
Sun Yimin
e25a8c6be2
sm9/bn256: arm64 ww-mm test 2023-06-26 17:28:02 +08:00
Sun Yimin
84f203d4ad
sm2ec: arm64 ww-mm test again 2023-06-26 16:47:57 +08:00
Sun Yimin
1ff7cb7b7f
sm2ec: arm64 trigger test 2023-06-26 16:41:12 +08:00
Sun Yimin
b19dfa6d58
sm2ec: arm64 test 2023-06-26 16:01:36 +08:00
emmansun
dbbfa37399 sm9/bn256: update document 2023-06-24 10:10:08 +08:00
emmansun
9b4a77482a sm9/bn256: add test cases and refactoring 2023-06-24 09:38:45 +08:00
emmansun
b84bd335dc sm9/bn256: amd64 support MULX for mul & Sqr 2023-06-22 18:54:09 +08:00
emmansun
f95cce434f sm9/bn256: fix arm64 from mont func issue 2023-06-22 15:50:06 +08:00
emmansun
531302450a sm9/bn256: check arm64 failed function 2023-06-22 15:36:42 +08:00
emmansun
edf3db15b6 sm9/bn256: did not save code change 2023-06-22 14:58:29 +08:00
emmansun
7b0e5c2bb9 sm9/bn256: remove useless code 2023-06-22 14:53:02 +08:00
emmansun
0bb1fa5be5 sm9/bn256: asm rewrite batch 1, for arm64 test 2023-06-22 14:35:14 +08:00
Sun Yimin
ecab517411
sm9/bn256: curvePointMovCond twistPointMovCond asm implementation for amd64 & arm64 2023-06-21 15:45:06 +08:00
Sun Yimin
aa535e3aaa
sm9/bn256: gfP12MovCond asm implementation for amd64 & arm64 2023-06-21 14:35:58 +08:00
Sun Yimin
9bcbf9bae9
sm2/sm9: eliminate bounds checks in the loop of Select 2023-06-21 11:52:32 +08:00
Sun Yimin
2da0a9cebc
sm9/bn256: add comment for gfpNeg 2023-06-21 09:02:09 +08:00
emmansun
5d101fb431 sm9: fix neg issue 2023-06-20 21:01:56 +08:00
Sun Yimin
4bda6e6b6c
sm3: improve purego performance 2023-06-20 17:51:14 +08:00
Sun Yimin
0ad84822fe
sm9/bn256: re-implement gfp generic 2023-06-20 17:48:04 +08:00
Sun Yimin
392e5fb762
Merge pull request #128 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.10.0
build(deps): bump golang.org/x/crypto from 0.9.0 to 0.10.0
2023-06-20 08:28:22 +08:00
dependabot[bot]
72fe9cd1e8
build(deps): bump golang.org/x/crypto from 0.9.0 to 0.10.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.9.0 to 0.10.0.
- [Commits](https://github.com/golang/crypto/compare/v0.9.0...v0.10.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-20 00:00:16 +00:00
Sun Yimin
72614b4d8b
sm4: cbc arm64 missing definition 2023-06-19 16:02:09 +08:00
Sun Yimin
f81bbd17df
sm4: improve arm64 single block performance & CBC decrypt performance 2023-06-19 15:51:49 +08:00
Sun Yimin
3cbabc3d1c
optimize purego sm3/sm4 and reduce bounds checking for sm9 2023-06-16 16:06:38 +08:00
Sun Yimin
3bd048c903
sm2ec: use asm to implement p256OrdReduce 2023-06-16 15:52:28 +08:00
Sun Yimin
0e667b152d
sm4: improve purego performance 2023-06-16 10:22:15 +08:00
Sun Yimin
50352995ae
sm2ec: fix comment 2023-06-15 21:50:25 +08:00
Sun Yimin
008e826fdf
zuc: reduce bounds checking 2023-06-15 16:47:50 +08:00
Sun Yimin
79f0fb6b0d
sm3: reduce bounds checking 2023-06-15 11:52:14 +08:00
Sun Yimin
c4e0e39475
sm9: fix npe issue 2023-06-15 11:23:06 +08:00
Sun Yimin
a1b44f1a64
sm9: get around assignment copies lock value to issue 2023-06-15 11:17:51 +08:00
Sun Yimin
66eae26312
sm2ec: arm64 register reuse issue 2023-06-14 17:53:13 +08:00
Sun Yimin
a8791437f8
sm2ec: fix arm64 func name issue 2023-06-14 17:43:27 +08:00
Sun Yimin
de14139590
sm2ec: p256ScalarMult change to use w=6 2023-06-14 17:30:58 +08:00
Sun Yimin
7f54c1e1a5
sm2ec: fix ScalarMult issue when scalar = N - 6 2023-06-13 13:24:43 +08:00
Sun Yimin
40dba3a488
Merge pull request #126 from emmansun/dependabot/go_modules/golang.org/x/sys-0.9.0
build(deps): bump golang.org/x/sys from 0.8.0 to 0.9.0
2023-06-13 08:22:23 +08:00
dependabot[bot]
e4e7eade14
build(deps): bump golang.org/x/sys from 0.8.0 to 0.9.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.8.0 to 0.9.0.
- [Commits](https://github.com/golang/sys/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-13 00:00:35 +00:00
Sun Yimin
5e794738ca
sm2ec: amd64 reduce duplicated codes 2023-06-12 09:04:09 +08:00
Sun Yimin
a0c4a389b8
sm2ec: optimize amd64 with MULX & AVX2 2023-06-10 10:55:17 +08:00
Sun Yimin
df8cb4d95d
bigmod: optimization for 256 bits 2023-06-07 09:43:20 +08:00
Sun Yimin
207fd1e7a4
drbg: fix drbg prng read issue when reseed 2023-06-07 08:32:46 +08:00
Sun Yimin
83849d33cf
sm4: fix bug 2023-06-05 14:46:59 +08:00
Sun Yimin
57d800767b
sm4: finetune bounds check 2023-06-05 14:32:15 +08:00
Sun Yimin
f3a5d48ed8
properly apply name constrains to roots and intermediates #125 2023-06-01 13:10:54 +08:00
Sun Yimin
36a92eff46
fix array len issue 2023-06-01 11:40:28 +08:00
Sun Yimin
88a158f61c
fix golang sdk version issue 2023-06-01 11:22:43 +08:00
Sun Yimin
0bf96ecea2
fix compile issue 2023-06-01 11:12:23 +08:00
Sun Yimin
f32b7e1afc
[sync sdk] crypto/internal/bigmod: switch to saturated limbs 2023-06-01 10:39:12 +08:00
Sun Yimin
f7a04e74a1
upgrade other actions/setup-go to v4 2023-05-24 17:29:59 +08:00
Sun Yimin
5817b08c43
Update ci.yml
upgrade actions/setup-go@v4 to support cache by default
2023-05-24 17:22:01 +08:00
Sun Yimin
6e9ba588f9
Merge pull request #122 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.9.0
build(deps): bump golang.org/x/crypto from 0.8.0 to 0.9.0
2023-05-16 08:43:24 +08:00
dependabot[bot]
fd26e4b1c2
build(deps): bump golang.org/x/crypto from 0.8.0 to 0.9.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.8.0 to 0.9.0.
- [Commits](https://github.com/golang/crypto/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-16 00:00:08 +00:00
emmansun
c3847c504f xor: use avx2 if possible 2023-05-13 10:26:44 +08:00
Sun Yimin
941b782448
Merge pull request #121 from emmansun/dependabot/go_modules/golang.org/x/sys-0.8.0
build(deps): bump golang.org/x/sys from 0.7.0 to 0.8.0
2023-05-09 08:25:18 +08:00
dependabot[bot]
5fb8d7b332
build(deps): bump golang.org/x/sys from 0.7.0 to 0.8.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.7.0 to 0.8.0.
- [Commits](https://github.com/golang/sys/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-09 00:00:32 +00:00
Sun Yimin
0a7f4d4779
Update README.md
发现提高没那么多
2023-05-04 09:02:23 +08:00
emmansun
ad80148a26 sm9: fix gfP12b6Gen error, not used yet 2023-05-03 11:24:07 +08:00
emmansun
12d604b54f sm9: add comment for mulLine 2023-05-02 14:04:00 +08:00
emmansun
0cf7d640c5 sm9: optimize mul line 2023-05-02 12:13:18 +08:00
emmansun
de6e4c2464 sm9: pairing 避免除数处理 2023-05-02 11:39:16 +08:00
emmansun
bf17ff1a4d sm9: need to further check 0 handling 2023-04-29 13:47:58 +08:00
emmansun
13ddfad8e4 sm9: optimize generate and gfP2 sqrt 2023-04-29 13:33:44 +08:00
emmansun
b197c96040 sm9: update README 2023-04-29 10:47:19 +08:00
emmansun
f58cb10ad9 sm9: improve gfP invert & sqrt performance 2023-04-29 10:30:57 +08:00
Sun Yimin
4a5dcf64c1
Update README.md 2023-04-28 20:13:53 +08:00
Sun Yimin
40f3928766
sm9: implement 1-2-6-12 towering extensions for comparison 2023-04-28 16:52:10 +08:00
Sun Yimin
eeaa257b1a
sm9: reduce mul, improve performance 2023-04-28 16:40:10 +08:00
Sun Yimin
946b85b409
sm9: reduce mul, improve performance 2023-04-28 15:31:59 +08:00
Sun Yimin
a454c5f5ec
sm9: reduce gfp2 mul 2023-04-28 11:25:09 +08:00
Sun Yimin
fab159f5f0
x509: use the RFC 6125 terminology in the VerifyHostname docs 2023-04-24 09:43:37 +08:00
Sun Yimin
33c6d26f07
fix nilness finding 2023-04-20 15:47:08 +08:00
Sun Yimin
75fde484ba
drbg: use hash creator, but it's still NOT goroutine safe 2023-04-13 09:32:14 +08:00
Sun Yimin
a4d7601bd9
Merge pull request #114 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.8.0
build(deps): bump golang.org/x/crypto from 0.7.0 to 0.8.0
2023-04-11 08:16:44 +08:00
dependabot[bot]
15b9269c08
build(deps): bump golang.org/x/crypto from 0.7.0 to 0.8.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.7.0 to 0.8.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-11 00:15:41 +00:00
Sun Yimin
36764970e7
Merge pull request #113 from emmansun/dependabot/go_modules/golang.org/x/sys-0.7.0
build(deps): bump golang.org/x/sys from 0.6.0 to 0.7.0
2023-04-11 08:15:01 +08:00
dependabot[bot]
8291cc5a37
build(deps): bump golang.org/x/sys from 0.6.0 to 0.7.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/sys/releases)
- [Commits](https://github.com/golang/sys/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-11 00:03:49 +00:00
Sun Yimin
7484123c90
smx509: remove unnecessary !Empty() check 2023-03-31 08:56:24 +08:00
Sun Yimin
e8c96eff71
add status badges 2023-03-30 17:04:27 +08:00
Sun Yimin
9c49aa43c3
rename action 2023-03-30 16:42:16 +08:00
Sun Yimin
9f7a0ac2b6
sm4: arm optimize rotateleft 2023-03-30 16:41:21 +08:00
Sun Yimin
01151be42e
sm4: fix gcm_sm4ni_arm64 dec bug 2023-03-30 15:46:37 +08:00
Sun Yimin
05ba968610
sm ni test all 2023-03-30 15:04:56 +08:00
Sun Yimin
7047aab300
sm3: fix rotateleft32 issue 2023-03-30 14:56:46 +08:00
Sun Yimin
d38216752d
sm3: fix arm ni issue 2023-03-30 14:05:04 +08:00
Sun Yimin
d2382247b1
sm3: fix arm ni issue 2023-03-30 13:39:17 +08:00
Sun Yimin
bb3529894c
sm3: fix arm sm3 ni issue 2023-03-30 13:03:31 +08:00
Sun Yimin
b2b56fae32
fix gcm sm4 ni bug 2023-03-30 11:46:19 +08:00
Sun Yimin
6b4c50e65a
try reduce one instr 2023-03-30 11:30:36 +08:00
Sun Yimin
3fed51e909
fix error 2023-03-30 11:26:34 +08:00
Sun Yimin
c52d700860
do not reverse byte order 2023-03-30 10:26:10 +08:00
Sun Yimin
0ec1d9cb40
do not reverse byte order 2023-03-30 10:06:56 +08:00
Sun Yimin
03e35209e8
retry not reverse byte order 2023-03-30 10:01:34 +08:00
Sun Yimin
334efa093d
test shangmi ni with qemu 2023-03-30 08:49:09 +08:00
Sun Yimin
f66d37654c
pkcs: update gcm parameters 2023-03-28 11:09:58 +08:00
Sun Yimin
af86ca7b7b
pkcs7: enable sign without attributes 2023-03-28 08:41:01 +08:00
Sun Yimin
d814868a47
pkcs: SM4 oid special handling 2023-03-27 13:41:45 +08:00
Sun Yimin
1ed0dbb068
sm2: make opts fields private 2023-03-22 17:29:16 +08:00
Sun Yimin
6254f0a5cb
sm2: update comments 2023-03-22 10:18:06 +08:00
Sun Yimin
adec7ac7e2
pkcs7: improve test coverage 2023-03-16 10:18:19 +08:00
Sun Yimin
c1289f7224
pkcs7: test clean 2023-03-15 17:50:27 +08:00
Sun Yimin
a93f7fd94d
pkcs7: reduce duplicated and useless code 2023-03-14 17:48:29 +08:00
Sun Yimin
652e6da354
pkcs7: reduce duplicated code 2023-03-14 08:36:15 +08:00
Sun Yimin
052f6ed2cf
cfca: supplement test cases 2023-03-13 13:57:22 +08:00
Sun Yimin
805d393d78
Update README.md 2023-03-11 12:41:47 +08:00
Sun Yimin
5d46f47c15
add cfca sm2 key and certificate parse 2023-03-10 17:09:29 +08:00
Sun Yimin
e7f1b45acf
pkcs7: signed and enveloped data, test rsa 2023-03-09 16:49:21 +08:00
Sun Yimin
1b956e2db0
pkcs7: de-support dsa 2023-03-09 15:07:17 +08:00
Sun Yimin
b70f6bb374
internal/sm2ec: fix test assert bug 2023-03-09 14:52:55 +08:00
Sun Yimin
1d1382f085
pkcs7: fix error 2023-03-09 14:32:50 +08:00
Sun Yimin
9a839b50c0
pkcs7: remove useless file 2023-03-09 14:24:01 +08:00
Sun Yimin
d968b80e5c
Fix sha1 test issue 2023-03-09 13:18:42 +08:00
Sun Yimin
236c37dab8
enable sha1 for test 2023-03-09 11:53:54 +08:00
Sun Yimin
5d41aaa348
merge pkcs7 2023-03-09 11:45:39 +08:00
Sun Yimin
7257b0151b
fix typo issu 2023-03-08 15:44:38 +08:00
Sun Yimin
818159283c
disable sm3 sm4 ni via env. variable 2023-03-08 15:39:48 +08:00
Sun Yimin
6bbcc97bd4
Create test_qemu.yml 2023-03-08 13:42:46 +08:00
Emman
784e14b59e Revert "[go1.17] internal/subtle xor 简化代码,去除重复 #75"
This reverts commit cedbf0c3557ec1c643b648dafefebb993854506e.
2023-03-08 10:24:34 +08:00
Sun Yimin
cedbf0c355
[go1.17] internal/subtle xor 简化代码,去除重复 #75 2023-03-08 10:10:28 +08:00
Sun Yimin
71657b8d34
fix possible test failure 2023-03-07 08:55:09 +08:00
Sun Yimin
08e9fb79c1
Merge pull request #107 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.7.0
build(deps): bump golang.org/x/crypto from 0.6.0 to 0.7.0
2023-03-07 08:23:10 +08:00
dependabot[bot]
8e66c1b2f8
build(deps): bump golang.org/x/crypto from 0.6.0 to 0.7.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 00:20:35 +00:00
Sun Yimin
ca7af068d1
Merge pull request #106 from emmansun/dependabot/go_modules/golang.org/x/sys-0.6.0
build(deps): bump golang.org/x/sys from 0.5.0 to 0.6.0
2023-03-07 08:20:02 +08:00
dependabot[bot]
2669b605ba
build(deps): bump golang.org/x/sys from 0.5.0 to 0.6.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/golang/sys/releases)
- [Commits](https://github.com/golang/sys/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 00:09:31 +00:00
Sun Yimin
f57e6a4a1d
pkcs8: rename internal struct 2023-03-06 17:18:55 +08:00
Sun Yimin
617d2591d6
pkcs8: fix gcm parameters asn1 issue 2023-02-28 13:43:00 +08:00
Sun Yimin
a47ae96293
sm2: SM2EnvelopedKey support 2023-02-22 17:37:56 +08:00
Sun Yimin
35a2ebe48f
internal/bigmod: flag amd64 assembly as noescape 2023-02-16 09:00:38 +08:00
Sun Yimin
21df52b623
smx9: rename CipherFactory to newCipher 2023-02-15 17:30:33 +08:00
Sun Yimin
dd8b2f61dd
smx509: ParseTypedECPrivateKey, return real privae key type 2023-02-14 16:03:05 +08:00
Sun Yimin
bf037a329e
sm9: handle empty plaintext and invalid ciphertext size 2023-02-14 10:45:02 +08:00
Sun Yimin
94cf65edbe
Merge pull request #102 from emmansun/dependabot/go_modules/golang.org/x/crypto-0.6.0
build(deps): bump golang.org/x/crypto from 0.5.0 to 0.6.0
2023-02-14 08:31:43 +08:00
dependabot[bot]
c2d16dcda5
build(deps): bump golang.org/x/crypto from 0.5.0 to 0.6.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-14 00:11:35 +00:00
Sun Yimin
2eb1c508b8
sm9: use correct method 2023-02-13 15:47:02 +08:00
Sun Yimin
d52750d7a8
sm9: fix decrypt method ASN1 format checking issue 2023-02-13 15:36:04 +08:00
Sun Yimin
aedef9d00d
sm9: refactor encrypter mode 2023-02-13 14:36:34 +08:00
Sun Yimin
ebf9a74d77
sm9: support non-xor modes 2023-02-10 17:19:50 +08:00
Sun Yimin
5bfdfeb9b5
sm9: add example test, fix unexpected line 2023-02-03 15:25:40 +08:00
Sun Yimin
d22b2253f3
sm9: add example test 2023-02-03 15:13:02 +08:00
Sun Yimin
cf0c739dcf
smx509: change CreateCertificate's template and parent parameter type to any 2023-02-03 10:25:03 +08:00
Sun Yimin
cb1e23a776
add example test for drbg, zuc 2023-02-02 15:58:31 +08:00
Sun Yimin
a2d54159ad
add example test for sm3 sm4 pkcs8 2023-02-02 11:45:57 +08:00
Sun Yimin
5b806c85fe
pkcs8: fix comments 2023-02-01 17:34:42 +08:00
Sun Yimin
ff2b695500
pkcs8: add example test 2023-02-01 17:28:49 +08:00
Sun Yimin
e3db7656a6
add example test for sm2 sm4 2023-02-01 11:17:23 +08:00
Sun Yimin
9c8b345630
Create dependabot.yml 2023-01-31 14:11:13 +08:00
Sun Yimin
edfb4febdd
sm: improve docs and add examples 2023-01-31 13:50:14 +08:00
Sun Yimin
72bb569234
smx509: clarify that CheckSignatureFrom and CheckSignature are low-level API 2023-01-18 11:07:03 +08:00
Sun Yimin
24d89df5c0
sm2: add a reference test method for non-standard keys construction 2023-01-16 11:01:55 +08:00
Sun Yimin
824748a293
sm2: use ReadASN1Integer instead of clone private code 2022-12-13 11:03:02 +08:00
Sun Yimin
5c12b08cd5
upgrade dependencies 2022-12-08 11:00:47 +08:00
Sun Yimin
ca18fb55f4
sm2: test decrypt error 2022-12-06 10:11:02 +08:00
Sun Yimin
97e419809e
sm9: ErrDecryption, avoid adaptive attacks 2022-12-06 08:54:53 +08:00
Sun Yimin
32acdfea7e
sm2: ErrDecryption, avoid adaptive attacks 2022-12-06 08:39:16 +08:00
Sun Yimin
60c3caf9db
sm2: align error message 2022-12-05 17:12:14 +08:00
Sun Yimin
d30cb1d1c8
sm9: add test cases 2022-12-02 15:49:48 +08:00
Sun Yimin
9c8836b2c6
sm9: sm9: use bigmod instead of math/big, verify method 2022-12-02 14:33:54 +08:00
Sun Yimin
acf6edec18
smx509: include more hints for verification failure 2022-12-02 08:47:39 +08:00
Sun Yimin
13f777bb2f
sm2: verify validity of signature parameters in Verify 2022-12-02 08:41:41 +08:00
Sun Yimin
9b3333f015
sm2: supplement test cases and upgrade dependencies 2022-11-30 09:00:17 +08:00
Sun Yimin
f95e558482
sm2: use equals instead of not equals 2022-11-29 10:35:18 +08:00
Sun Yimin
18e2f1b022
sm9: improve test coverage 2022-11-28 10:55:23 +08:00
Sun Yimin
98646cfac0
sm9: deprecated sign/verify non-asn1 methods 2022-11-28 10:32:17 +08:00
Sun Yimin
c477816aa7
sm9: use bigmod instead of math/big, part 2 2022-11-25 17:45:11 +08:00
Sun Yimin
a592631459
sm9: do not expose internal constants 2022-11-25 14:40:27 +08:00
Sun Yimin
63668bb045
sm9: remove duplicated code 2022-11-25 10:27:21 +08:00
Sun Yimin
d7e853277a
sm9: use bigmod instead of math/big 2022-11-25 10:11:46 +08:00
Sun Yimin
aede405cdd
sm2: add deprecated comment 2022-11-24 10:18:03 +08:00
Sun Yimin
fc8fe5c631
sm2/enc: use bigmod and sm2ec instead of math/big and crypto/elliptic 2022-11-23 17:34:08 +08:00
Sun Yimin
9c6638f30e
fix error path 2022-11-23 10:28:36 +08:00
Sun Yimin
3bd57e44f4
move file 2022-11-23 10:21:29 +08:00
Sun Yimin
a45e13d148
sm2: use bigmod and sm2ec instead of math/big and crypto/elliptic 2022-11-23 10:20:13 +08:00
Sun Yimin
200a785d29
change build tag generic to purego & import nat package 2022-11-22 11:02:37 +08:00
Sun Yimin
57882bbdbc
sm3: reduce Write calls in Sum 2022-11-22 08:42:17 +08:00
Sun Yimin
f1993bc41a
sm2,smx509: add encoding paths for SM2 ecdh keys 2022-11-21 10:09:57 +08:00
Sun Yimin
984913e228
sm2,smx509: add encoding paths for SM2 ecdh keys 2022-11-21 09:31:30 +08:00
Sun Yimin
9805aa448a
x509: create CRLs with Issuer.RawSubject 2022-11-18 11:45:46 +08:00
Sun Yimin
7448a5de1e
ecdh: format sm2 curve constans 2022-11-18 11:24:06 +08:00
Sun Yimin
17b873a345
x509: Reallow duplicate attributes in CSRs. 2022-11-18 10:43:39 +08:00
Sun Yimin
94087a6660
x509: Reallow duplicate attributes in CSRs. 2022-11-18 10:28:22 +08:00
Sun Yimin
289bfe16c0
x509: add support for PKCS8/PKIX X25519 key encodings preparation 2022-11-18 10:21:25 +08:00
Sun Yimin
6c7ddbb206
ecdh: move ECDH method to PrivateKey 2022-11-18 09:43:51 +08:00
Sun Yimin
c4540b0c31
add name constraints test 2022-11-15 14:48:49 +08:00
Sun Yimin
68e297f49b
remove unused member Raw from certificate, #95 2022-11-15 11:09:01 +08:00
Sun Yimin
8f6804d73f
upgrade dependencies 2022-11-15 09:24:44 +08:00
Sun Yimin
b7c636b87d
export ParseName for tls/tlcp to parse certificate authorities 2022-11-09 16:18:08 +08:00
Sun Yimin
7490af1dca
review x509 and readme 2022-11-03 11:12:26 +08:00
Sun Yimin
4f5968f7ce
add disclaimer 2022-11-03 09:41:36 +08:00
Sun Yimin
1ce7714cc9
rollback first #93 2022-11-02 17:11:18 +08:00
Sun Yimin
fd940fcd06
fix failed case for golang < 1.18.x 2022-11-02 16:56:06 +08:00
Sun Yimin
8b25009e6f
respect GODEBUG changes for allowing SHA1 certificates #93 2022-11-02 16:42:50 +08:00
Sun Yimin
d11a8bc940
supplement test coverage 2022-11-01 16:08:17 +08:00
Sun Yimin
cf6a25bf31
fix bug 2022-11-01 15:38:28 +08:00
Sun Yimin
096578c771
improve readability 2022-11-01 09:49:15 +08:00
Sun Yimin
cae2dbea35
use sample test to make sure correctness 2022-10-31 14:44:38 +08:00
emmansun
82326621ee add proxy methods for rsa pkcs1 pub/priv keys 2022-10-30 11:38:17 +08:00
emmansun
0f0eec19d0 provide a sample method to handle irregular ciphertext #90 2022-10-30 09:46:09 +08:00
Sun Yimin
57d01255e8
handle padding zero, #90 2022-10-28 09:31:41 +08:00
Sun Yimin
9ba3e69efc
update error messages 2022-10-24 17:32:56 +08:00
Sun Yimin
4ba1372fa0
update comments 2022-10-24 16:31:26 +08:00
Sun Yimin
5db7e63360
provide convient methods to parse pkcs8 sm9 keys 2022-10-24 16:09:12 +08:00
Sun Yimin
a7c36d7f30
supplement gmssl sign master private key test data 2022-10-24 11:45:46 +08:00
Sun Yimin
f6af6eb729
add gmssl test cases 2022-10-24 11:42:26 +08:00
Sun Yimin
d35482a358
pkcs8 sm9 master sign/encrypt private key support 2022-10-24 11:00:13 +08:00
emmansun
404cd10210 support sm9 key format with gmssl 2022-10-22 15:49:01 +08:00
Sun Yimin
ecdf5fca82
supplement tesst cases 2022-10-21 10:46:18 +08:00
Sun Yimin
0342ada322
add comments and enhance gm validation 2022-10-21 10:22:10 +08:00
Sun Yimin
7f86563f74
update README.md and dependencies 2022-10-20 16:28:58 +08:00
Sun Yimin
afc4750bf0
Sample pseudo random number generator base on DRBG 2022-10-20 15:28:06 +08:00
Sun Yimin
643df78c07
implement ctr drbg 2022-10-20 11:30:20 +08:00
Sun Yimin
f723aa8c66
hash drbg initial version 2022-10-19 09:57:58 +08:00
Sun Yimin
6253b828c7
upgrade dependencies and remove useless code 2022-10-11 13:27:56 +08:00
Sun Yimin
49f25af421
add parallel test 2022-09-16 11:48:28 +08:00
Sun Yimin
0946644542
update readme 2022-09-08 08:56:26 +08:00
Sun Yimin
8f7a7626ba
sm2: support ecdh mqv 2022-09-02 14:03:51 +08:00
Sun Yimin
6a556b26d3
smx509: don't panic marshaling invalid ECDSA keys #81 2022-08-30 10:35:57 +08:00
Sun Yimin
fb7041acbc
sm2/9: key exchange destroy, fix #80 2022-08-30 09:54:29 +08:00
Sun Yimin
3f9e1d5bd9
ecdh: sm2 ECDH initial version 2022-08-26 13:25:56 +08:00
Sun Yimin
d1e4806e06
sm2: refactoring, reduce duplicated codes 2022-08-25 16:54:30 +08:00
Sun Yimin
8948bdd931
sm2: refactoring to reduce duplicated code 2022-08-25 16:45:18 +08:00
Sun Yimin
4a21345e72
sm9: fix compile error 2022-08-25 12:58:02 +08:00
Sun Yimin
7ebdf00640
fix defect 2022-08-25 12:54:59 +08:00
Sun Yimin
eedd5ebc2b
kdf: move Kdf() from sm3 to kdf 2022-08-25 11:48:41 +08:00
Sun Yimin
8f5dcb842e
sm2: key exchange refactoring 2022-08-24 16:53:11 +08:00
Sun Yimin
21a9793600
sm2/sm9: key exchange, support to destroy internal state 2022-08-24 15:15:58 +08:00
Sun Yimin
35154c8b53
remove useless ci 2022-08-19 15:07:56 +08:00
Sun Yimin
f2245485bc
Merge pull request #78 from emmansun/20221015
Upgrade minimum supported golang version to 1.16
2022-08-19 15:05:45 +08:00
Sun Yimin
f5cee483d5
align go verions in main 2022-08-19 15:03:28 +08:00
Sun Yimin
474168700e
sm2 ke: make sure the peer pub key using same curve 2022-08-19 11:39:02 +08:00
Sun Yimin
45d6a74b6a
update comment 2022-08-19 10:30:19 +08:00
Sun Yimin
8083b440cb
README: add go version and update travis label 2022-08-19 08:31:12 +08:00
Sun Yimin
6db1b23eb1
subtle: fix generic bug 2022-08-18 15:00:11 +08:00
Sun Yimin
1710bdff4a
refactoring, rename internal packages 2022-08-18 14:49:35 +08:00
Sun Yimin
b96e51e3ff
sm2: supplement test cases 2022-08-18 10:54:25 +08:00
Sun Yimin
ae12f04c14
sm2: use golang 1.19 style marshal/unmarshal 2022-08-18 09:12:00 +08:00
Sun Yimin
37f3e129da
use golang 1.19 feature 2022-08-17 15:58:06 +08:00
Sun Yimin
a507f61c7c
fix bug 2022-08-17 15:30:21 +08:00
Sun Yimin
c2efe31957
move ci file 2022-08-17 15:27:19 +08:00
Sun Yimin
93dca77af8
sync code from sm2fiat and branch 1.16 2022-08-17 15:23:59 +08:00
Sun Yimin
c88bad8c7d
sm2/9 key exchange: test no sign/verify case 2022-08-17 11:36:50 +08:00
Sun Yimin
3f550e2f24
sm2/9: key exchange error message and comment 2022-08-17 11:17:18 +08:00
Sun Yimin
fb53e7eb71
sm2: key exchange fix bug & add comments 2022-08-16 11:46:08 +08:00
Sun Yimin
bed0b64629
sm2ec: error message 2022-08-15 15:21:42 +08:00
Sun Yimin
f254673618
sm2ec: sync with sdk 2022-08-15 15:16:07 +08:00
Sun Yimin
c37e143c66
Merge pull request #73 from Trisia/main
SM2密钥交换方法初始化
2022-08-14 11:22:52 +08:00
cliven
a6172852fc 修改了设置对端参数名称,增加了防止重复设置的检查。 2022-08-14 11:10:55 +08:00
cliven
eea15c3e4c SM2密钥交换算法支持了初始化时没有对端公开信息,在后续加入公开信息的方法。 2022-08-13 15:18:47 +08:00
Sun Yimin
b299ca46f2
zuc: constant time & correct lazy mod 2022-08-10 13:52:44 +08:00
Sun Yimin
b7cc21a055
sm3: kdf constant time check all zero 2022-08-09 15:58:55 +08:00
Sun Yimin
05aeed5c34
sm9: marshal compressed 2022-08-09 10:01:34 +08:00
Sun Yimin
f437855de0
add unit test case and fix typo 2022-08-03 16:31:02 +08:00
Sun Yimin
2071214f1f
x509: fix error message 2022-08-02 15:09:34 +08:00
Sun Yimin
8d0ee45571
upgrade dependencies 2022-07-28 10:39:55 +08:00
Sun Yimin
818cbc3757
misc: clean code 2022-07-28 10:01:30 +08:00
Sun Yimin
21859b7273
sm4: gcm data disable pass initial tag 2022-07-28 09:37:03 +08:00
Sun Yimin
5b075213c0
sm4: add cbcEncAble interface 2022-07-26 08:30:24 +08:00
Sun Yimin
206c8075c3
sm4: arm64 use VZIP1 VZIP2 to transpose matrix 2022-07-25 17:10:15 +08:00
Sun Yimin
fd34c2eff2
sm4: arm64 transpose matrix use VZIP1 VZIP2 2022-07-25 16:37:23 +08:00
Sun Yimin
9b364dca8b
sm4: reduce duplicated code and add comments 2022-07-25 13:20:58 +08:00
Sun Yimin
9204f1f4b2
sm4: encryptBlockAsm arm64 optimization 2022-07-22 15:17:05 +08:00
Sun Yimin
f0ad4beb49
sm4: add gcm test cases from GB/T 36624-2018 C.5 2022-07-22 11:25:18 +08:00
Sun Yimin
acffd83cc9
sm4: format asm code 2022-07-22 10:08:15 +08:00
Sun Yimin
ff434b7bd7
sm4: arm64 forget to load IV 2022-07-21 17:37:57 +08:00
Sun Yimin
42faebb588
sm4: cbc encryption improvement a little 2022-07-21 17:32:11 +08:00
Sun Yimin
8ddf1bc68f
sm4: reduce duplicated asm code 2022-07-21 13:41:56 +08:00
Sun Yimin
572bf6574e
sm4: improve cbc decrypt performance 2022-07-20 11:43:49 +08:00
Sun Yimin
54a06d72e1
sm9: test all curves 2022-07-19 16:07:42 +08:00
Sun Yimin
ec7f96d3cc
sm9: remove unsure code 2022-07-19 15:36:08 +08:00
Sun Yimin
af50b136e9
sm4: separate cipher_ni from cipher_asm 2022-07-19 13:29:21 +08:00
Sun Yimin
6a60fe2603
ccm: add unit test cases and support ignore 2022-07-19 09:47:36 +08:00
Sun Yimin
711508985e
sm9: clean code and unit test 2022-07-19 08:58:12 +08:00
Sun Yimin
24765d0e35
supplement unit test cases 2022-07-18 10:13:53 +08:00
Sun Yimin
be29c32fe5
Update README.md 2022-07-17 17:48:02 +08:00
Sun Yimin
08bb2e2b57
zuc: add test case 2022-07-15 17:18:14 +08:00
Emman
fdb89d3233 Merge branch 'main' of https://github.com/emmansun/gmsm 2022-07-15 16:43:38 +08:00
Emman
eb94980db3 run "gofmt -s -w" 2022-07-15 16:42:39 +08:00
Sun Yimin
221cd0f6d2
Create codeql-analysis.yml 2022-07-15 14:22:31 +08:00
Sun Yimin
ffe5bff24e
pkcs8: fix copy issue 2022-07-15 13:37:54 +08:00
Sun Yimin
7271ce6df9
pkcs8: find out race fail case due to big CostParameter value 2022-07-15 13:34:42 +08:00
Sun Yimin
1a75fd65ca
zuc: add comment and fix a bug 2022-07-15 11:48:44 +08:00
Sun Yimin
7e81d05ce9
[sync] crypto/x509: restrict CRL number to <=20 octets #69 2022-07-15 10:25:53 +08:00
Sun Yimin
99bfac3a2b
upgrade dependencies and add unit test cases 2022-07-14 15:31:49 +08:00
Sun Yimin
58513465fa
x509: supplement test cases 2022-07-14 15:03:15 +08:00
Sun Yimin
204419818f
zuc: fix a copy paste error 2022-07-14 14:17:41 +08:00
Sun Yimin
9751e9619e
zuc: EIA256 ARM64 2022-07-14 14:10:49 +08:00
Sun Yimin
e0b2121574
zuc: eia arm64 2022-07-14 10:45:43 +08:00
Sun Yimin
c6e33cb31c
zuc: eia arm64 2022-07-14 10:42:49 +08:00
Sun Yimin
b1dd0ade2e
zuc: eia256 performance improvement 2022-07-13 16:16:01 +08:00
Sun Yimin
39274df2bd
zuc: EIA performance improvement 2022-07-13 11:51:44 +08:00
Sun Yimin
87f6f6a736
sm4: fix test case issue 2022-07-12 10:08:23 +08:00
Sun Yimin
daa6853722
sm4: add test cases 2022-07-12 09:57:35 +08:00
Sun Yimin
e4d02321b7
test: try coverpkg 2022-07-12 08:38:01 +08:00
Sun Yimin
189f2217c3
sm4: remove sm4_test folder 2022-07-11 17:40:48 +08:00
Sun Yimin
8eeeddbbea
cipher/sm4: refactoring, remove sm4_test folder 2022-07-11 17:40:15 +08:00
Sun Yimin
2c3b759652
upgrade github actions 2022-07-11 16:40:11 +08:00
Sun Yimin
74f18edc53
try merge generic report 2022-07-11 16:01:41 +08:00
Sun Yimin
b36779c604
change to use codecov/codecov-action@v3 2022-07-11 15:53:47 +08:00
Sun Yimin
1e4171b1e8
code test coverage 2022-07-11 15:42:11 +08:00
Sun Yimin
8bcbb9c77a
code test coverage 2022-07-11 14:25:20 +08:00
Sun Yimin
394991c8b1
Update ci.yml 2022-07-11 13:55:27 +08:00
Sun Yimin
ceaa727f83
go report card 2022-07-11 13:32:34 +08:00
Sun Yimin
6efc68c6a9
go report card 2022-07-11 13:28:23 +08:00
Sun Yimin
7bf006ca42
go report card 2022-07-11 13:27:36 +08:00
Sun Yimin
f51e5cca1f
zuc: eia refactoring 2022-07-08 16:08:43 +08:00
Sun Yimin
38db8cebd3
zuc: arm64 fix bug 2022-07-07 14:20:09 +08:00
Sun Yimin
80638ed2ae
zuc: arm64 debug 1 2022-07-07 14:10:05 +08:00
Sun Yimin
f169de84de
zuc: try to arm64 2022-07-07 13:44:10 +08:00
Sun Yimin
d79c799dad
zuc: test arm64 2022-07-07 13:07:22 +08:00
Sun Yimin
eca13ba8c5
[sm9] fix 32-bit GOARCH issue 2022-07-07 11:43:00 +08:00
Emman
1ccbc35f12 Revert "[sm9] fix 32-bit GOARCH issue"
This reverts commit 53b24e0aaccaed0d3f3c4f04ead2121363afa91f.
2022-07-07 11:28:44 +08:00
Sun Yimin
53b24e0aac
[sm9] fix 32-bit GOARCH issue 2022-07-07 10:50:24 +08:00
Sun Yimin
4734c4a670
zuc: init arm64 2022-07-06 10:50:57 +08:00
Sun Yimin
08d5d28bae
zuc: reduce one XOR & rename one function 2022-07-05 12:34:49 +08:00
Sun Yimin
83c6a58365
zuc: amd64 performance improvement 3 2022-07-01 11:00:42 +08:00
Sun Yimin
ff4e5e9606
zuc: update readme 2022-06-30 11:40:51 +08:00
Sun Yimin
bd2543cdf9
zuc: amd64 optimization step 2 2022-06-30 11:29:42 +08:00
Sun Yimin
f7a55494c8
zuc: amd64 optimization step 1 2022-06-29 17:36:07 +08:00
Sun Yimin
68f38a96af
zuc: optimize function call 2022-06-23 15:53:24 +08:00
Sun Yimin
b4b9cd07d9
key exchange refactoring 2022-06-23 10:24:10 +08:00
Sun Yimin
461f4b6838
sm9: improve performance according sparse elements 2022-06-22 15:36:46 +08:00
Sun Yimin
f5bc1d657e
zuc: performance improvement 1 2022-06-21 15:58:47 +08:00
Sun Yimin
195f6f73ba
sm9: change finalExponentiation implementation 2022-06-20 13:34:53 +08:00
Sun Yimin
974ba65845
sm2: generic use new method first 2022-06-20 11:34:05 +08:00
Sun Yimin
3e2158f68d
fix package issue 2022-06-20 11:19:59 +08:00
Sun Yimin
ae9d85d2f0
sm2: use new implementation, part 1 2022-06-20 11:15:09 +08:00
Sun Yimin
0136fdcabf
forgot one file 2022-06-20 09:45:34 +08:00
Sun Yimin
e06e5ef47b
key exchange refactoring, reduce duplicated code 2022-06-20 09:42:48 +08:00
Sun Yimin
23914a86c3
SM2: key exchange 2022-06-17 16:58:26 +08:00
Sun Yimin
21b8f82a6e
pkcs8: merge from emmansun/pkcs8 2022-06-17 10:59:23 +08:00
Sun Yimin
823cf4a470
test: reduce fmt.Printf 2022-06-17 08:49:50 +08:00
Sun Yimin
aa9e546638
SM9: update readme and supplement comment 2022-06-16 16:40:00 +08:00
Sun Yimin
410b1eea3a
SM9: add key exchange support 2022-06-16 14:43:28 +08:00
Sun Yimin
81c0dbb0fa
SM9: refactoring, move separate SM9 & bn256 2022-06-16 10:14:45 +08:00
Sun Yimin
3320de17b8
SM9: supplement comment and sample test case 2022-06-16 08:46:28 +08:00
Sun Yimin
14af2513d8
SM9: G1 G2 support point compress 2022-06-15 15:17:16 +08:00
Sun Yimin
0ea5fa3966
Merge pull request #62 from opensvn/main
change the function name and use the correct verb
2022-06-15 14:30:18 +08:00
opensvn
e5150e19b5 change the function name and use the correct verb 2022-06-15 13:40:30 +08:00
Sun Yimin
b77041404d
test cases to original file 2022-06-14 14:36:58 +08:00
Sun Yimin
35fb02af53
fix own error 2022-06-14 14:25:01 +08:00
Sun Yimin
7bd1a3823e
try fix arm64 2022-06-14 14:19:35 +08:00
Sun Yimin
dcb4dadd47
check arm64 mul 2022-06-14 12:13:27 +08:00
Sun Yimin
4c532200a9
try again 2022-06-14 11:44:06 +08:00
Sun Yimin
4f2585ddbc
check arm64 gfp 2022-06-14 11:03:54 +08:00
Sun Yimin
554621915d
try to find out arm64 fail root cause 2022-06-14 09:59:59 +08:00
Sun Yimin
9f5752e5d7
find out arm64 asm failed method 2022-06-14 09:52:20 +08:00
Sun Yimin
5d5e5603bd
remove travis ppc64le CI 2022-06-14 09:01:52 +08:00
Sun Yimin
f5bd2cabad
fix 1.17 error 2022-06-14 08:57:25 +08:00
Sun Yimin
8cb1e257dc
support build generic 2022-06-14 08:45:54 +08:00
Sun Yimin
2d64b499cb
Update ci.yml 2022-06-14 08:18:58 +08:00
Sun Yimin
ccdb7b0568
supplement user key generation performance 2022-06-13 17:35:46 +08:00
Sun Yimin
d6a464f470
precompute part 2 2022-06-13 16:29:58 +08:00
Sun Yimin
2b0119dda7
Upgrade dependencies 2022-06-13 14:44:36 +08:00
Sun Yimin
f78fd3c105
precompute part 1 2022-06-13 13:50:27 +08:00
Sun Yimin
cadc48f630
Update README.md 2022-06-11 07:49:11 +08:00
Sun Yimin
dff29c24c6
chang to use NAF method in miller loop 2022-06-10 14:44:51 +08:00
Sun Yimin
e8d3b67446
sm9 sign wrappkey encryption 2022-06-10 11:24:25 +08:00
Sun Yimin
ef51a679a7
extract kdf to sm3 2022-06-10 10:29:12 +08:00
Sun Yimin
6b8782ddf1
fix error 2022-06-09 09:28:46 +08:00
Sun Yimin
936c19772e
temp solution for darwin 2022-06-09 09:11:43 +08:00
Sun Yimin
163fb51082
as a temp solution for darwin 2022-06-09 09:03:49 +08:00
Sun Yimin
6e769eeaf1
Create macos.yml 2022-06-09 08:28:48 +08:00
Sun Yimin
109f6e7110
rollback 2022-06-07 17:46:14 +08:00
Sun Yimin
602c0e9b18
comment failed cases first 2022-06-07 17:45:05 +08:00
Sun Yimin
68fa329262
Update ci.yml 2022-06-07 17:39:42 +08:00
Sun Yimin
2ad4ddb506
Update ci.yml 2022-06-07 17:38:29 +08:00
Sun Yimin
f4913888c9
Update ci.yml 2022-06-07 17:29:27 +08:00
Sun Yimin
ca8961c13e
Update ci.yml 2022-06-07 17:27:31 +08:00
Sun Yimin
337575950e
add endofline 2022-06-07 17:22:59 +08:00
Sun Yimin
7254c055d7
sm9 foundation 2022-06-07 17:13:23 +08:00
Sun Yimin
92439288cb
fix #57 2022-06-06 13:45:46 +08:00
Sun Yimin
bb0f4f7996
refactoring, align error message pattern 2022-05-27 17:46:14 +08:00
Sun Yimin
255b3d3e7e
upgrade dependencies 2022-05-20 08:22:19 +08:00
Sun Yimin
14e38f9aa5
code copy issue 2022-05-18 17:42:26 +08:00
Sun Yimin
e7bfecaf49
remove util.go 2022-05-18 15:58:09 +08:00
Sun Yimin
c5982357d3
avoid slice again 2022-05-18 15:43:08 +08:00
Sun Yimin
01063b1ff7
use golang sdk as much as possible 2022-05-18 15:33:33 +08:00
Sun Yimin
fc1411a702
fix assembly that clobbers BP 2022-05-18 09:05:02 +08:00
Sun Yimin
8fda97f991
p256Inverse using addchain generated code 2022-05-16 12:51:43 +08:00
Sun Yimin
60f734b82c
disable signing with MD5WithRSA #56 2022-05-13 08:22:35 +08:00
Sun Yimin
ff60ecbcc8
Upgrade dependencies 2022-05-13 08:06:51 +08:00
Sun Yimin
5b5942db84
refactor point marshal/unmarshal 2022-05-11 16:58:36 +08:00
Sun Yimin
dafbb30c6e
use SAN when comparing certs during path building, #55 2022-05-09 14:47:23 +08:00
Sun Yimin
322aa881ed
EKU nesting enforcement, #54 2022-05-09 14:35:51 +08:00
emmansun
57d899613d align format 2022-05-01 18:06:47 +08:00
emmansun
488c0db854 remove branch ci 2022-05-01 17:31:44 +08:00
Sun Yimin
9a2d7123f8
Merge pull request #52 from emmansun/sm3_sm4_ni
Sm3 sm4 ni
2022-05-01 16:19:35 +08:00
Emman
c71d5ccd96 Fix compile error 2022-04-29 17:29:08 +08:00
Emman
37ab6d67f3 Fix amd64 bug 2022-04-29 13:01:34 +08:00
Emman
51b26c071d separate aes/sm4 ni implementation 2022-04-29 12:09:04 +08:00
Emman
f2c249b323 refactoring and fix bug 2022-04-29 09:10:16 +08:00
Emman
4c131bdeb6 refactoring and fix bug 2022-04-29 08:56:53 +08:00
Emman
0beb90aff8 enable sm4ni gcm 2022-04-28 17:53:04 +08:00
Emman
5744b64c56 sm4ni gcm 2022-04-28 17:52:11 +08:00
Emman
0450200249 sm4 use sm4e sm4ekey, without gcm integration part 2022-04-28 13:46:50 +08:00
Emman
697d1dbd35 sm3 use arm cpu inst 2022-04-28 13:44:18 +08:00
Emman
1d83736209 add branch ci 2022-04-28 13:43:44 +08:00
Emman
660d54649b fix generated asm file name pattern 2022-04-28 11:03:44 +08:00
Emman
67d40a2a61 add new line 2022-04-27 10:42:20 +08:00
Emman
47f411681c upgrade dependency 2022-04-27 10:38:59 +08:00
Emman
c266b3211a support sm3 ni preparation 2022-04-27 10:36:10 +08:00
Emman
2dc8dae6bd Update comments 2022-04-26 10:13:17 +08:00
Emman
eb56eac42a support zuc eia 256 bits 2022-04-26 10:04:30 +08:00
Emman
7632ebf376 sm4 generic implementation optimization ref openssl 2022-04-25 11:02:33 +08:00
Emman
03563d8553 zuc128 eia for reference 2022-04-22 11:31:59 +08:00
Emman
41d0934ef4 crypto/x509: revert serial length restriction 2022-04-22 08:37:49 +08:00
Emman
64f522ea1b Revert "#43, crypto/x509: don't allow too long serials"
This reverts commit b3f10b9a4cfeb8c384282f3e61aaf7356efab636.

# Conflicts:
#	smx509/x509.go
#	smx509/x509_test.go
2022-04-22 08:28:12 +08:00
Emman
88dc7dc8ec remove non-shangmi alg 2022-04-21 08:27:41 +08:00
Emman
0a827de266 update package level comments 2022-04-20 08:36:44 +08:00
Emman
772beacfb0 support zuc256 for eea 2022-04-19 17:42:21 +08:00
Emman
ca98bd6f5c crypto/x509: reject duplicate extensions #48 2022-04-19 16:29:41 +08:00
Emman
45aae847b8 add back the last test vector 2022-04-19 13:32:09 +08:00
Emman
2391806012 Merge branch 'main' of https://github.com/emmansun/gmsm 2022-04-19 11:50:38 +08:00
Emman
133077a4b2 zuc 128 stream cipher 2022-04-19 11:25:14 +08:00
Emman
e95fc0c08a rc5 symmetric cipher 2022-04-19 11:24:00 +08:00
emmansun
77f61fce9c crypto/x509: don't create certs with negative serials #47 2022-04-17 09:37:03 +08:00
Emman
35732a2822 #45, #46 2022-04-15 11:14:30 +08:00
Emman
155ef2943d #44, crypto/x509: omit empty extensions SEQUENCE 2022-04-15 11:05:14 +08:00
Emman
b3f10b9a4c #43, crypto/x509: don't allow too long serials 2022-04-15 11:01:11 +08:00
Emman
db4ee8585a expose type cast method 2022-04-13 09:41:38 +08:00
Emman
51f29b0258 Upgrade dependencies 2022-04-13 09:40:42 +08:00
emmansun
c7066d2256 fix ut error 2022-04-11 19:50:44 +08:00
Emman
efc3350236 Fix ut error 2022-04-11 17:40:41 +08:00
Emman
97217e8a68 crypto/x509: only disable SHA-1 verification for certificates 2022-04-11 17:33:40 +08:00
Emman
41f9220e3c crypto/x509: rework path building 2022-04-11 15:55:23 +08:00
Emman
eb54032c1b crypto/x509: properly handle issuerUniqueID and subjectUniqueID 2022-04-11 13:36:14 +08:00
Emman
d35a314b7a crypto/x509: properly handle issuerUniqueID and subjectUniqueID 2022-04-11 13:35:04 +08:00
Emman
bd9ba93ffe crypto/x509: add CertPool.Equal 2022-04-11 13:34:35 +08:00
Emman
a61731e0e2 duplicated 2022-04-10 11:16:11 +08:00
Emman
0f7a9070ee pkcs1 2022-04-10 09:56:28 +08:00
Emman
dc34e17797 tolerate zero-padded scalars in generic implementation 2022-04-08 11:18:45 +08:00
Emman
bfdb74af01 Upgrade dependencies 2022-04-08 10:51:32 +08:00
Emman
fc6fce3bbf Test Issue 52075 - generic impl panic when scalar has too many leading zeroes 2022-04-08 10:50:11 +08:00
Emman
6450e27784 Upgrade dependencies 2022-03-25 14:35:18 +08:00
Emman
f375365553 Upgrade dependencies 2022-03-21 10:14:28 +08:00
Emman
0357a17c0a crypto/x509: return err ans1.Marshal gives an error 2022-03-21 10:13:40 +08:00
Emman
d79ab3d709 Change to use new {M1, C1, M2, C2}, do not know the old one's derivation process 2022-03-11 18:05:08 +08:00
Emman
9d2fd48255 Upgrade dependencies 2022-03-11 08:26:36 +08:00
Emman
90547cbb23 Add comments 2022-03-09 08:49:41 +08:00
Emman
8fd965965c Upgrade dependencies 2022-03-09 08:48:42 +08:00
558 changed files with 117553 additions and 15438 deletions

8
.github/codecov.yaml vendored Normal file
View File

@ -0,0 +1,8 @@
codecov:
require_ci_to_pass: yes
ignore:
- "sm2/gen_p256_table.go"
- "sm4/sm4ni_gcm_asm.go"
- "sm4/cipher_ni.go"
- "docs"

21
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,21 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gomod" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily
- package-ecosystem: docker
directory: /internal/sm2ec/fiat
schedule:
interval: daily

View File

@ -6,34 +6,69 @@ on:
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
goVer: ['1.15', '1.16', '1.17']
goVer: ['1.23', '1.24']
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- name: Checkout Repo
uses: actions/checkout@v2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ matrix.goVer }}
- name: Setup Environment
run: |
echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Module cache
uses: actions/cache@v2.1.7
- name: Test with Coverage
if: ${{ matrix.goVer == '1.24' }}
run: go test -coverpkg=./... -v -short -race -coverprofile=coverage1.txt -covermode=atomic ./...
env:
cache-name: go-mod-cache
GODEBUG: x509sha1=1
- name: Test Generic with Coverage
if: ${{ matrix.goVer == '1.24' }}
run: go test -coverpkg=./... -v -short -tags purego -coverprofile=coverage2.txt -covermode=atomic ./...
env:
GODEBUG: x509sha1=1
- name: Upload coverage to Codecov
if: ${{ matrix.goVer == '1.24' }}
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/go.sum') }}
- name: Test
run: go test -v ./...
files: ./coverage1.txt,./coverage2.txt
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- name: Test Force SM4 Single Block with AES-NI
run: go test -short ./sm4/...
env:
FORCE_SM4BLOCK_AESNI: 1
- name: Test only
if: ${{ matrix.goVer != '1.24' }}
run: go test -short ./...
env:
GODEBUG: x509sha1=1
- name: Test Generic only
if: ${{ matrix.goVer != '1.24' }}
run: go test -short -tags purego ./...
env:
GODEBUG: x509sha1=1
- name: Test Plugin only
if: ${{ matrix.goVer == '1.24' }}
run: go test -short -tags plugin ./...
env:
GODEBUG: x509sha1=1

48
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,48 @@
name: "CodeQL"
on:
workflow_dispatch:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
- cron: '30 1 * * *'
permissions:
contents: read
jobs:
CodeQL-Build:
permissions:
actions: read # for github/codeql-action/init to get workflow details
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/autobuild to send a status report
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
with:
languages: go
- name: Autobuild
uses: github/codeql-action/autobuild@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0

29
.github/workflows/licenses.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: Update License File
on:
push:
branches: [ main ]
paths:
- 'go.mod'
- 'go.sum'
permissions:
contents: read
jobs:
update-licenses:
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: '1.23'
- name: Install go-licenses
run: go install github.com/google/go-licenses@latest
- name: Generate license files
run: |
go-licenses report github.com/emmansun/gmsm > third-party-licenses.md

36
.github/workflows/macos.yml vendored Normal file
View File

@ -0,0 +1,36 @@
name: macOs
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
build:
runs-on: macos-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: 1.23
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...
env:
GODEBUG: x509sha1=1
GOARCH: ${{ matrix.arch }}

83
.github/workflows/scorecard.yml vendored Normal file
View File

@ -0,0 +1,83 @@
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '32 2 * * 2'
push:
branches: [ "main" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
# `publish_results: true` only works when run from the default branch. conditional can be removed if disabled.
if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request'
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- name: "Checkout code"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore
# file_mode: git
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
with:
sarif_file: results.sarif

51
.github/workflows/test_ppc64.yaml vendored Normal file
View File

@ -0,0 +1,51 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: ppc64le-qemu
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
test:
strategy:
matrix:
go-version: [1.23.x]
arch: [ppc64le]
ppc64: [power8]
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ matrix.go-version }}
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Test internal
run: go test -v ./internal/...
env:
GOARCH: ${{ matrix.arch }}
GOPPC64: ${{ matrix.ppc64 }}
- name: Test Cipher
run: go test -v -short ./cipher/...
env:
GOARCH: ${{ matrix.arch }}
GOPPC64: ${{ matrix.ppc64 }}

53
.github/workflows/test_qemu.yml vendored Normal file
View File

@ -0,0 +1,53 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: arm64-qemu
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
test:
strategy:
matrix:
go-version: [1.23.x]
arch: [arm64]
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ matrix.go-version }}
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Test
run: go test -v -short ./...
env:
DISABLE_SM3NI: 1
DISABLE_SM4NI: 1
GODEBUG: x509sha1=1
GOARCH: ${{ matrix.arch }}
- name: Test Force SM4 Single Block with AES-NI
run: go test -v -short ./sm4/...
env:
DISABLE_SM4NI: 1
FORCE_SM4BLOCK_AESNI: 1
GOARCH: ${{ matrix.arch }}

44
.github/workflows/test_riscv64.yaml vendored Normal file
View File

@ -0,0 +1,44 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: riscv64-qemu
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
test:
strategy:
matrix:
go-version: [1.23.x]
arch: [riscv64]
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ matrix.go-version }}
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Test
run: go test -v -short ./internal/...
env:
GODEBUG: x509sha1=1
GOARCH: ${{ matrix.arch }}

57
.github/workflows/test_s390x.yaml vendored Normal file
View File

@ -0,0 +1,57 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: s390x-qemu
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
test:
strategy:
matrix:
go-version: [1.23.x]
arch: [s390x]
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ matrix.go-version }}
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Test internal
run: go test -v ./internal/...
env:
GOARCH: ${{ matrix.arch }}
- name: Test Cipher
run: go test -v -short ./cipher/...
env:
GOARCH: ${{ matrix.arch }}
# - name: Test
# run: go test -v -short ./...
# env:
# GODEBUG: x509sha1=1
# GOARCH: ${{ matrix.arch }}

44
.github/workflows/test_sm_ni.yml vendored Normal file
View File

@ -0,0 +1,44 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: sm3-sm4-ni-qemu
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
test:
strategy:
matrix:
go-version: [1.23.x]
arch: [arm64]
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
with:
egress-policy: audit
- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ matrix.go-version }}
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Test
run: go test -v -short ./...
env:
GODEBUG: x509sha1=1
GOARCH: ${{ matrix.arch }}

View File

@ -1,22 +0,0 @@
language: go
jobs:
include:
- arch: ppc64le
go: 1.17.x
- arch: arm64-graviton2
virt: vm
os: linux
dist: focal
go: 1.15.x
group: edge
install:
- go mod tidy
- go mod download
script:
- go test -v -short ./...
#after_success:
# - go test -v -short -bench . -run=^$ ./...

8
CITATION.cff Normal file
View File

@ -0,0 +1,8 @@
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
authors:
- family-names: "Sun"
given-names: "Yimin"
title: "gmsm"
date-released: 2021-1-20
url: "https://github.com/emmansun/gmsm"

27
DISCLAIMER.md Normal file
View File

@ -0,0 +1,27 @@
# 免责声明
## 版权声明
本项目(gmsm)代码的版权归[Sun Yimin](mailto:emman.sun@foxmail.com)所有,并按照[MIT](https://github.com/emmansun/gmsm/blob/main/LICENSE)进行分发。使用本项目的代码时,必须遵守相应的许可证条款。
## 免责条款
1. **无担保声明**
本项目以“原样”提供,不提供任何形式的明示或暗示担保,包括但不限于对适销性、特定用途适用性和非侵权性的担保。
2. **责任限制**
对于因使用或无法使用本项目代码而导致的任何直接、间接、偶然、特殊、典型或惩罚性损害(包括但不限于数据丢失、利润损失、业务中断等),项目作者或贡献者概不负责。
3. **使用风险**
使用本项目代码的风险由使用者自行承担。使用者在使用本项目时,应自行评估代码的适用性和安全性,并根据实际需求进行测试和调整。
4. **第三方依赖**
本项目可能依赖于第三方库或服务,这些库或服务的使用应遵守其各自的许可证条款。项目作者或贡献者不对第三方库或服务的稳定性、安全性或合法性负责。
5. **法律合规**
使用本项目代码时,使用者应确保遵守所在国家或地区的法律法规。如因使用本项目代码而违反相关法律,使用者需自行承担法律责任。
6. **产品认证**
本项目(gmsm)**没有**经过相关机构(包括但不限于**国家密码管理局商用密码检测中心**)认证,也不承诺会进行相关认证工作。
7. **修改与分发**
如果您修改本项目代码并重新分发,请确保保留上述版权声明和免责条款,并明确标注您的修改内容。

73
README-EN.md Normal file
View File

@ -0,0 +1,73 @@
# GM-Standards SM2/SM3/SM4/SM9/ZUC for Go
[![Github CI](https://github.com/emmansun/gmsm/actions/workflows/ci.yml/badge.svg)](https://github.com/emmansun/gmsm/actions/workflows/ci.yml)
[![arm64-qemu](https://github.com/emmansun/gmsm/actions/workflows/test_qemu.yml/badge.svg)](https://github.com/emmansun/gmsm/actions/workflows/test_qemu.yml)
[![sm3-sm4-ni-qemu](https://github.com/emmansun/gmsm/actions/workflows/test_sm_ni.yml/badge.svg)](https://github.com/emmansun/gmsm/actions/workflows/test_sm_ni.yml)
[![codecov](https://codecov.io/gh/emmansun/gmsm/branch/main/graph/badge.svg?token=Otdi8m8sFj)](https://codecov.io/gh/emmansun/gmsm)
[![Go Report Card](https://goreportcard.com/badge/github.com/emmansun/gmsm)](https://goreportcard.com/report/github.com/emmansun/gmsm)
[![Documentation](https://godoc.org/github.com/emmansun/gmsm?status.svg)](https://godoc.org/github.com/emmansun/gmsm)
![GitHub go.mod Go version (branch)](https://img.shields.io/github/go-mod/go-version/emmansun/gmsm)
[![Release](https://img.shields.io/github/release/emmansun/gmsm/all.svg)](https://github.com/emmansun/gmsm/releases)
English | [简体中文](README.md)
ShangMi (SM) cipher suites for Golang, referred to as **GMSM**, is a secure, high-performance, easy-to-use Golang ShangMi (SM) cipher suites library, covering public algorithms SM2/SM3/SM4/SM9/ZUC.
## Packages
- **SM2** - This is a SM2 sm2p256v1 implementation whose performance is similar like golang native NIST P256 under **amd64**, **arm64**, **s390x** and **ppc64le**, for implementation detail, please refer [SM2实现细节](https://github.com/emmansun/gmsm/wiki/SM2%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96). It supports ShangMi sm2 digital signature, public key encryption algorithm and also key exchange.
- **SM3** - This is also a SM3 implementation whose performance is similar like golang native SHA 256 with SIMD under **amd64**, **arm64**, **s390x**, **ppc64x**, for implementation detail, please refer [SM3性能优化](https://github.com/emmansun/gmsm/wiki/SM3%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96). It also provides A64 cryptographic instructions SM3 tested with QEMU.
- **SM4** - For SM4 implementation, SIMD & AES-NI are used under **amd64**, **arm64** and **ppc64x**, for detail please refer [SM4性能优化](https://github.com/emmansun/gmsm/wiki/SM4%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96). It is optimized for **ECB/CBC/GCM/XTS** operation modes. It also provides A64 cryptographic instructions SM4 tested with QEMU.
- **SM9** - For SM9 implementation, please reference [SM9实现及优化](https://github.com/emmansun/gmsm/wiki/SM9%E5%AE%9E%E7%8E%B0%E5%8F%8A%E4%BC%98%E5%8C%96)
- **ZUC** - For ZUC implementation, SIMD, AES-NI and CLMUL are used under **amd64**, **arm64** and **ppc64x**, for detail please refer [Efficient Software Implementations of ZUC](https://github.com/emmansun/gmsm/wiki/Efficient-Software-Implementations-of-ZUC)
- **CBCMAC** - CBC-MAC and its variants (EMAC/ANSI retail MAC/MacDES/CMAC/LMAC/TrCBC/CBCR).
- **CFCA** - some cfca specific implementations.
- **CIPHER** - ECB/CCM/XTS/HCTR/BC/OFBNLF operation modes, XTS mode also supports **GB/T 17964-2021**. Current XTS mode implementation is **NOT** concurrent safe! **BC** and **OFBNLF** are legacy operation modes, **HCTR** is new operation mode in **GB/T 17964-2021**. **BC** operation mode is similar like **CBC**, there is no room for performance optimization in **OFBNLF** operation mode.
- **SMX509** - a fork of golang X509 that supports ShangMi.
- **PKCS7** - a fork of [mozilla-services/pkcs7](https://github.com/mozilla-services/pkcs7) that supports ShangMi.
- **PKCS8** - a fork of [youmark/pkcs8](https://github.com/youmark/pkcs8) that supports ShangMi.
- **ECDH** - a similar implementation of golang ECDH that supports SM2 ECDH & SM2MQV without usage of **big.Int**, a replacement of SM2 key exchange. For detail, pleaes refer [is my code constant time?](https://github.com/emmansun/gmsm/wiki/is-my-code-constant-time%3F)
- **DRBG** - Random Number Generation Using Deterministic Random Bit Generators, for detail, please reference **NIST Special Publication 800-90A** and **GM/T 0105-2021**: CTR-DRBG using derivation function and HASH-DRBG. NIST related implementations are tested with part of NIST provided test vectors. It's **NOT** concurrent safe! You can also use [randomness](https://github.com/Trisia/randomness) tool to check the generated random bits.
- **MLDSA** - NIST FIPS 204 Module-Lattice-Based Digital Signature Standard.
- **SLHDSA** - NIST FIPS 205 Stateless Hash-Based Digital Signature Standard
## Some Related Projects
- **[TLCP](https://github.com/Trisia/gotlcp)** - An implementation of **GB/T 38636-2020 Information security technology Transport Layer Cryptography Protocol (TLCP)**.
- **[Trisia/Randomness](https://github.com/Trisia/randomness)** - An implementation of **GM/T 0005-2021 Randomness test specification**.
- **[PKCS12](https://github.com/emmansun/go-pkcs12)** - pkcs12 supports ShangMi, a fork of [SSLMate/go-pkcs12](https://github.com/SSLMate/go-pkcs12).
- **[MKSMCERT](https://github.com/emmansun/mksmcert)** - A simple tool for making locally-trusted development ShangMi certificates, a fork of [FiloSottile/mkcert](https://github.com/FiloSottile/mkcert).
## License
This work is licensed under a MIT License. See the [LICENSE](./LICENSE) file for details.
## Acknowledgements
The basic architecture, design and some codes are from [golang crypto](https://github.com/golang/go/commits/master/src/crypto).
The SM4 amd64 SIMD AES-NI implementation is inspired by code from [mjosaarinen/sm4ni](https://github.com/mjosaarinen/sm4ni).
The original SM9/BN256 version is based on code from [cloudflare/bn256](https://github.com/cloudflare/bn256).
The ZUC amd64 SIMD AES-NI, CLMUL implementation is inspired by code from [Intel(R) Multi-Buffer Crypto for IPsec Library](https://github.com/intel/intel-ipsec-mb/).
The pkcs7 is based on code from [mozilla-services/pkcs7](https://github.com/mozilla-services/pkcs7), which has been archived by the owner on Feb 10, 2024.
The pkcs8 is based on code from [youmark/pkcs8](https://github.com/youmark/pkcs8).
## Disclaimer
This library is not fully audited and is offered as-is, and without a guarantee. Therefore, it is expected that changes in the code, repository, and API occur in the future. We recommend to take caution before using this library in a production application.
## Stargazers over time
[![Stargazers over time](https://starchart.cc/emmansun/gmsm.svg?variant=adaptive)](https://starchart.cc/emmansun/gmsm)

194
README.md
View File

@ -1,104 +1,90 @@
# GM-Standards SM2/SM3/SM4 for Go
[![Travis CI](https://app.travis-ci.com/emmansun/gmsm.svg?branch=main)](https://app.travis-ci.com/emmansun/gmsm)
[![Github CI](https://github.com/emmansun/gmsm/actions/workflows/ci.yml/badge.svg)](https://github.com/emmansun/gmsm/actions/workflows/ci.yml)
[![Documentation](https://godoc.org/github.com/emmansun/gmsm?status.svg)](https://godoc.org/github.com/emmansun/gmsm)
[![Release](https://img.shields.io/github/release/emmansun/gmsm/all.svg)](https://github.com/emmansun/gmsm/releases)
This is a **SM2 sm2p256v1** implementation whose performance is similar like golang native NIST P256 under **amd64** and **arm64**, for implementation detail, please refer [SM2实现细节](https://github.com/emmansun/gmsm/wiki/SM2%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96).
This is also a **SM3** implementation whose performance is similar like golang native SHA 256 with SIMD under **amd64**, for implementation detail, please refer [SM3性能优化](https://github.com/emmansun/gmsm/wiki/SM3%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96).
For **SM4** implementation, SIMD & AES-NI are used under **amd64** and **arm64**, for detail please refer [SM4性能优化](https://github.com/emmansun/gmsm/wiki/SM4%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96), support CBC/CFB/OFB/CTR/GCM/CCM/XTS modes.
**SM2 encryption Benchmark**
CPU: i5-9500
P-256/SM2(No tuning)
goos: windows
goarch: amd64
pkg: gmsm/sm2
BenchmarkLessThan32-6 210 5665861 ns/op 0.01 MB/s 2601864 B/op 27725 allocs/op
PASS
ok gmsm/sm2 5.629s
P-256/SM2(with P256/SM2 curve pure golang implementation)
goos: windows
goarch: amd64
pkg: gmsm/sm2
BenchmarkLessThan32_P256SM2-6 1027 1169516 ns/op 3874 B/op 74 allocs/op
PASS
ok gmsm/sm2 1.564s
P-256/SM2(with P256/SM2 amd64 curve implementation, i think there are still improvement space for p256Sqr function)
goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm2
BenchmarkLessThan32_P256SM2-6 10447 115618 ns/op 2357 B/op 46 allocs/op
PASS
ok github.com/emmansun/gmsm/sm2 2.199s
P-256 (SM2 based on NIST P-256 curve)
goos: windows
goarch: amd64
pkg: gmsm/sm2
BenchmarkMoreThan32-6 13656 86252 ns/op 3141 B/op 50 allocs/op
PASS
ok gmsm/sm2 4.139s
**SM3 hash Benchmark**
CPU: i5-9500
Pure golang version
goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm3
BenchmarkHash8K-6 27097 41112 ns/op 199.26 MB/s 0 B/op 0 allocs/op
PASS
ok github.com/emmansun/gmsm/sm3 3.463s
ASM (non-AVX2) version
goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm3
BenchmarkHash8K-6 35080 33235 ns/op 246.49 MB/s 0 B/op 0 allocs/op
PASS
ok github.com/emmansun/gmsm/sm3 3.102s
ASM AVX2 version
goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm3
BenchmarkHash8K-6 53208 22223 ns/op 368.63 MB/s 0 B/op 0 allocs/op
PASS
ok github.com/emmansun/gmsm/sm3 1.720s
SHA256 ASM AVX2 version
goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm3
BenchmarkHash8K_SH256-6 68352 17116 ns/op 478.63 MB/s 0 B/op 0 allocs/op
PASS
ok github.com/emmansun/gmsm/sm3 3.043s
**SM4 Benchmark**
CPU: i5-9500
Pure golang version
goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm4
BenchmarkEncrypt-6 2671431 441 ns/op 36.28 MB/s 0 B/op 0 allocs/op
BenchmarkDecrypt-6 2709132 440 ns/op 36.40 MB/s 0 B/op 0 allocs/op
BenchmarkExpand-6 2543746 471 ns/op 16 B/op 1 allocs/op
ASM AES-NI version
goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm4
BenchmarkEncrypt-6 5881989 206 ns/op 77.75 MB/s 0 B/op 0 allocs/op
BenchmarkDecrypt-6 5853994 204 ns/op 78.45 MB/s 0 B/op 0 allocs/op
BenchmarkExpand-6 5985129 200 ns/op 0 B/op 0 allocs/op
PASS
ok github.com/emmansun/gmsm/sm4 6.193s
# Go语言商用密码软件
[![Github CI](https://github.com/emmansun/gmsm/actions/workflows/ci.yml/badge.svg)](https://github.com/emmansun/gmsm/actions/workflows/ci.yml)
[![arm64-qemu](https://github.com/emmansun/gmsm/actions/workflows/test_qemu.yml/badge.svg)](https://github.com/emmansun/gmsm/actions/workflows/test_qemu.yml)
[![sm3-sm4-ni-qemu](https://github.com/emmansun/gmsm/actions/workflows/test_sm_ni.yml/badge.svg)](https://github.com/emmansun/gmsm/actions/workflows/test_sm_ni.yml)
[![codecov](https://codecov.io/gh/emmansun/gmsm/branch/main/graph/badge.svg?token=Otdi8m8sFj)](https://codecov.io/gh/emmansun/gmsm)
[![Go Report Card](https://goreportcard.com/badge/github.com/emmansun/gmsm)](https://goreportcard.com/report/github.com/emmansun/gmsm)
[![Documentation](https://godoc.org/github.com/emmansun/gmsm?status.svg)](https://godoc.org/github.com/emmansun/gmsm)
![GitHub go.mod Go version (branch)](https://img.shields.io/github/go-mod/go-version/emmansun/gmsm)
[![Release](https://img.shields.io/github/release/emmansun/gmsm/all.svg)](https://github.com/emmansun/gmsm/releases)
[English](README-EN.md) | 简体中文
Go语言商用密码软件简称**GMSM**一个安全、高性能、易于使用的Go语言商用密码软件库涵盖商用密码公开算法SM2/SM3/SM4/SM9/ZUC。
## 用户文档
- [SM2椭圆曲线公钥密码算法应用指南](./docs/sm2.md)
- [SM3密码杂凑算法应用指南](./docs/sm3.md)
- [SM4分组密码算法应用指南](./docs/sm4.md)
- [SM9标识密码算法应用指南](./docs/sm9.md)
- [ZUC祖冲之序列密码算法应用指南](./docs/zuc.md)
- [CFCA互操作性指南](./docs/cfca.md)
- [PKCS7应用指南](./docs/pkcs7.md)
- [PKCS12应用指南](./docs/pkcs12.md)
如果你想提问题,建议你阅读[提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md)。
## 包结构
- **SM2** - SM2椭圆曲线公钥密码算法曲线的具体实现位于[internal/sm2ec](https://github.com/emmansun/gmsm/tree/main/internal/sm2ec) package中。SM2曲线实现性能和Golang标准库中的NIST P256椭圆曲线原生实现非BoringCrypto类似也对**amd64****arm64****s390x**和**ppc64le**架构做了专门汇编优化实现,您也可以参考[SM2实现细节](https://github.com/emmansun/gmsm/wiki/SM2%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96)及相关Wiki和代码以获得更多实现细节。SM2包实现了SM2椭圆曲线公钥密码算法的数字签名算法、公钥加密算法、密钥交换算法以及《GB/T 35276-2017信息安全技术 SM2密码算法使用规范》中的密钥对保护数据格式。
- **SM3** - SM3密码杂凑算法实现。**amd64**下分别针对**AVX2+BMI2、AVX、SSE2+SSSE3**做了消息扩展部分的SIMD实现 **arm64**下使用NEON指令做了消息扩展部分的SIMD实现同时也提供了基于**A64扩展密码指令**的汇编实现;**s390x**和**ppc64x**通过向量指令做了消息扩展部分的优化实现。您也可以参考[SM3性能优化](https://github.com/emmansun/gmsm/wiki/SM3%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96)及相关Wiki和代码以获得更多实现细节。
- **SM4** - SM4分组密码算法实现。**amd64**下使用**AES**指令加上**AVX2、AVX、SSE2+SSSE3**实现了比较好的性能。**arm64**下使用**AES**指令加上NEON指令实现了比较好的性能同时也提供了基于**A64扩展密码指令**的汇编实现。**ppc64x**下使用**vsbox**指令加上向量指令进行了并行优化。针对**ECB/CBC/GCM/XTS**加密模式做了和SM4分组密码算法的融合汇编优化实现。您也可以参考[SM4性能优化](https://github.com/emmansun/gmsm/wiki/SM4%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96)及相关Wiki和代码以获得更多实现细节。
- **SM9** - SM9标识密码算法实现。基础的素域、扩域、椭圆曲线运算以及双线性对运算位于[bn256](https://github.com/emmansun/gmsm/tree/main/sm9/bn256)包中,分别对**amd64**、**arm64**、**ppc64x**架构做了优化实现。您也可以参考[SM9实现及优化](https://github.com/emmansun/gmsm/wiki/SM9%E5%AE%9E%E7%8E%B0%E5%8F%8A%E4%BC%98%E5%8C%96)及相关讨论和代码以获得更多实现细节。SM9包实现了SM9标识密码算法的密钥生成、数字签名算法、密钥封装机制和公钥加密算法、密钥交换协议。
- **ZUC** - 祖冲之序列密码算法实现。使用SIMD、AES指令以及无进位乘法指令分别对**amd64**、**arm64**和**ppc64x**架构做了优化实现, 您也可以参考[ZUC实现及优化](https://github.com/emmansun/gmsm/wiki/Efficient-Software-Implementations-of-ZUC)和相关代码以获得更多实现细节。ZUC包实现了基于祖冲之序列密码算法的机密性算法、128/256位完整性算法。
- **CBCMAC** - 符合《GB/T 15852.1-2020 采用分组密码的机制》的消息鉴别码。
- **CFCA** - CFCA中金特定实现目前实现的是SM2私钥、证书封装处理对应SADK中的**PKCS12_SM2**信封加密、签名CSR生成及返回私钥解密、解析等功能。
- **CIPHER** - ECB/CCM/XTS/HCTR/BC/OFBNLF加密模式实现。XTS模式同时支持NIST规范和国标 **GB/T 17964-2021**。当前的XTS模式由于实现了BlockMode其结构包含一个tweak数组所以其**不支持并发使用**。**分组链接BC模式**和**带非线性函数的输出反馈OFBNLF模式**为分组密码算法的工作模式标准**GB/T 17964**的遗留模式,**带泛杂凑函数的计数器HCTR模式**是**GB/T 17964-2021**中的新增模式。分组链接BC模式和CBC模式类似而带非线性函数的输出反馈OFBNLF模式的话从软件实现的角度来看基本没有性能优化的空间。
- **SMX509** - Go语言X509包的分支加入了商用密码支持。
- **PADDING** - 一些填充方法实现(非常量时间运行):**pkcs7**,这是当前主要使用的填充方式,对应**GB/T 17964-2021**的附录C.2 填充方法 1**iso9797m2**,对应**GB/T 17964-2021**的附录C.3 填充方法 2**ansix923**对应ANSI X9.23标准。**GB/T 17964-2021**的附录C.4 填充方法 3对应ISO/IEC_9797-1 padding method 3。
- **PKCS7** - [mozilla-services/pkcs7](https://github.com/mozilla-services/pkcs7) 项目该项目已于2024年2月10日被归档的分支加入了商用密码支持。
- **PKCS8** - [youmark/pkcs8](https://github.com/youmark/pkcs8)项目的分支,加入了商用密码支持。
- **ECDH** - 一个类似Go语言中ECDH包的实现支持SM2椭圆曲线密码算法的ECDH & SM2MQV协议该实现没有使用 **big.Int**也是一个SM2包中密钥交换协议实现的替换实现推荐使用
- **DRBG** - 《GM/T 0105-2021软件随机数发生器设计指南》实现。本实现同时支持**NIST Special Publication 800-90A**(部分) 和 **GM/T 0105-2021**NIST相关实现使用了NIST提供的测试数据进行测试。本实现**不支持并发使用**。
- **MLDSA** - NIST FIPS 204 Module-Lattice-Based Digital Signature Standard实现。
- **SLHDSA** - NIST FIPS 205 Stateless Hash-Based Digital Signature Standard实现。
## 相关项目
- **[Trisia/TLCP](https://github.com/Trisia/gotlcp)** - 一个《GB/T 38636-2020 信息安全技术 传输层密码协议》Go语言实现项目。
- **[Trisia/Randomness](https://github.com/Trisia/randomness)** - 一个Go语言随机性检测规范实现。
- **[PKCS12](https://github.com/emmansun/go-pkcs12)** - [SSLMate/go-pkcs12](https://github.com/SSLMate/go-pkcs12)项目的一个分支加入了商用密码支持由于PKCS12标准比较老安全性不高所以以独立项目进行维护。
- **[MKSMCERT](https://github.com/emmansun/mksmcert)** - 一个用于生成SM2私钥和证书的工具主要用于开发测试它是[FiloSottile/mkcert](https://github.com/FiloSottile/mkcert)项目的一个分支,加入了商用密码支持。
- **JavaScript实现**
- [jsrsasign-sm](https://github.com/emmansun/sm2js) 扩展[jsrsasign](https://github.com/kjur/jsrsasign)实现的优势在于充分利用jsrsasign的PKIXCSRCERTPKCS8等处理能力。
- [sjcl-sm](https://github.com/emmansun/sm4js) 扩展[sjcl](https://github.com/bitwiseshiftleft/sjcl)实现的优势在于其丰富的对称加密模式实现,以及其简洁的代码、较好的性能。
## 软件许可
本软件使用MIT许可证详情请参考[软件许可](./LICENSE)。如果不熟悉MIT许可证条款请参考[MIT许可证](https://zh.wikipedia.org/zh-cn/MIT%E8%A8%B1%E5%8F%AF%E8%AD%89)。请知晓和遵守**被许可人义务**
## 致谢
本项目的基础架构、设计和部分代码源自[golang crypto](https://github.com/golang/go/commits/master/src/crypto).
SM4分组密码算法**amd64** SIMD AES-NI实现SSE部分的算法源自[mjosaarinen/sm4ni](https://github.com/mjosaarinen/sm4ni)。
SM9/BN256最初版本的代码复制自[cloudflare/bn256](https://github.com/cloudflare/bn256)项目,后期对基础的素域、扩域、椭圆曲线运算等进行了重写。
祖冲之序列密码算法实现**amd64** SIMD AES-NI, CLMUL实现算法源自[Intel(R) Multi-Buffer Crypto for IPsec Library](https://github.com/intel/intel-ipsec-mb/)项目。
PKCS7包代码是[mozilla-services/pkcs7](https://github.com/mozilla-services/pkcs7)项目该项目已于2024年2月10日被归档的一个分支加入了商用密码扩展。
PKCS8包代码是[youmark/pkcs8](https://github.com/youmark/pkcs8)项目的一个分支,加入了商用密码扩展。
## 免责声明
使用本项目前,请务必仔细阅读[GMSM软件免责声明](DISCLAIMER.md)
## 项目星标趋势
[![Stargazers over time](https://starchart.cc/emmansun/gmsm.svg?variant=adaptive)](https://starchart.cc/emmansun/gmsm)

7
SECURITY.md Normal file
View File

@ -0,0 +1,7 @@
# Security Policy
If you find a significant vulnerability, or evidence of one,
please report it privately.
We prefer that you use the [GitHub mechanism for privately reporting a vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability). Under the
[main repository's security tab](https://github.com/emmansun/gmsm/security), click "Report a vulnerability" to open the advisory form.

498
cbcmac/cbcmac.go Normal file
View File

@ -0,0 +1,498 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// Package cbcmac implements the Message Authentication Code with the block chipher mechanisms.
package cbcmac
import (
"crypto/cipher"
"crypto/subtle"
"github.com/emmansun/gmsm/padding"
)
// Reference: GB/T 15821.1-2020 Security techniques
// Message authentication codes - Part 1: Mechanisms using block ciphers
// BlockCipherMAC is the interface that wraps the basic MAC method.
type BlockCipherMAC interface {
// Size returns the MAC value's number of bytes.
Size() int
// MAC calculates the MAC of the given data.
// The MAC value's number of bytes is returned by Size.
// Intercept message authentication code as needed.
MAC(src []byte) []byte
}
// cbcmac implements the basic CBC-MAC mode of operation for block ciphers.
type cbcmac struct {
b cipher.Block
pad padding.Padding
size int
}
// NewCBCMAC returns a CBC-MAC (GB/T 15821.1-2020 MAC scheme 1) instance that
// implements the MAC with the given block cipher. The padding scheme is ISO/IEC 9797-1 method 2.
func NewCBCMAC(b cipher.Block, size int) BlockCipherMAC {
return NewCBCMACWithPadding(b, size, padding.NewISO9797M2Padding)
}
// NewCBCMACWithPadding creates a new CBC-MAC (Cipher Block Chaining Message Authentication Code)
// with the specified block cipher, MAC size, and padding function. The MAC size must be greater
// than 0 and less than or equal to the block size of the cipher. If the size is invalid, the
// function will panic. The padding function is used to pad the input to the block size of the cipher.
func NewCBCMACWithPadding(b cipher.Block, size int, newPaddingFunc padding.NewPaddingFunc) BlockCipherMAC {
if size <= 0 || size > b.BlockSize() {
panic("cbcmac: invalid size")
}
return &cbcmac{b: b, pad: newPaddingFunc(uint(b.BlockSize())), size: size}
}
func (c *cbcmac) Size() int {
return c.size
}
// MAC calculates the MAC of the given data.
// The data is padded with the padding scheme of the block cipher before processing.
func (c *cbcmac) MAC(src []byte) []byte {
src = c.pad.Pad(src)
blockSize := c.b.BlockSize()
tag := make([]byte, blockSize)
for len(src) > 0 {
subtle.XORBytes(tag, tag, src[:blockSize])
c.b.Encrypt(tag, tag)
src = src[blockSize:]
}
return tag[:c.size]
}
// emac implements the EMAC mode of operation for block ciphers.
type emac struct {
pad padding.Padding
b1, b2 cipher.Block
size int
}
// NewEMAC returns an EMAC (GB/T 15821.1-2020 MAC scheme 2) instance that
// implements MAC with the given block cipher. The padding scheme is ISO/IEC 9797-1 method 2.
func NewEMAC(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int) BlockCipherMAC {
return NewEMACWithPadding(creator, key1, key2, size, padding.NewISO9797M2Padding)
}
// NewEMACWithPadding creates a new instance of EMAC (Encrypted Message Authentication Code) with padding.
func NewEMACWithPadding(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int, newPaddingFunc padding.NewPaddingFunc) BlockCipherMAC {
var b1, b2 cipher.Block
var err error
if b1, err = creator(key1); err != nil {
panic(err)
}
if size <= 0 || size > b1.BlockSize() {
panic("cbcmac: invalid size")
}
if b2, err = creator(key2); err != nil {
panic(err)
}
return &emac{pad: newPaddingFunc(uint(b1.BlockSize())), b1: b1, b2: b2, size: size}
}
func (e *emac) Size() int {
return e.size
}
func (e *emac) MAC(src []byte) []byte {
src = e.pad.Pad(src)
blockSize := e.b1.BlockSize()
tag := make([]byte, blockSize)
for len(src) > 0 {
subtle.XORBytes(tag, tag, src[:blockSize])
e.b1.Encrypt(tag, tag)
src = src[blockSize:]
}
e.b2.Encrypt(tag, tag)
return tag[:e.size]
}
type ansiRetailMAC emac
// NewANSIRetailMAC returns an ANSI Retail MAC (GB/T 15821.1-2020 MAC scheme 3) instance that
// implements MAC with the given block cipher. The padding scheme is ISO/IEC 9797-1 method 2.
func NewANSIRetailMAC(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int) BlockCipherMAC {
return NewANSIRetailMACWithPadding(creator, key1, key2, size, padding.NewISO9797M2Padding)
}
// NewANSIRetailMACWithPadding creates a new ANSI Retail MAC with padding.
func NewANSIRetailMACWithPadding(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int, newPaddingFunc padding.NewPaddingFunc) BlockCipherMAC {
return (*ansiRetailMAC)(NewEMACWithPadding(creator, key1, key2, size, newPaddingFunc).(*emac))
}
func (e *ansiRetailMAC) Size() int {
return e.size
}
func (e *ansiRetailMAC) MAC(src []byte) []byte {
src = e.pad.Pad(src)
blockSize := e.b1.BlockSize()
tag := make([]byte, blockSize)
for len(src) > 0 {
subtle.XORBytes(tag, tag, src[:blockSize])
e.b1.Encrypt(tag, tag)
src = src[blockSize:]
}
e.b2.Decrypt(tag, tag)
e.b1.Encrypt(tag, tag)
return tag[:e.size]
}
type macDES struct {
pad padding.Padding
b1, b2, b3 cipher.Block
size int
}
// NewMACDES returns a MAC-DES (GB/T 15821.1-2020 MAC scheme 4) instance that
// implements MAC with the given block cipher. The padding scheme is ISO/IEC 9797-1 method 2.
func NewMACDES(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int) BlockCipherMAC {
return NewMACDESWithPadding(creator, key1, key2, size, padding.NewISO9797M2Padding)
}
// NewMACDESWithPadding creates a new BlockCipherMAC using DES encryption with padding.
func NewMACDESWithPadding(creator func(key []byte) (cipher.Block, error), key1, key2 []byte, size int, newPaddingFunc padding.NewPaddingFunc) BlockCipherMAC {
var b1, b2, b3 cipher.Block
var err error
if b1, err = creator(key1); err != nil {
panic(err)
}
if size <= 0 || size > b1.BlockSize() {
panic("cbcmac: invalid size")
}
if b2, err = creator(key2); err != nil {
panic(err)
}
key3 := make([]byte, len(key2))
copy(key3, key2)
for i := range key3 {
key3[i] ^= 0xF0
}
if b3, err = creator(key3); err != nil {
panic(err)
}
return &macDES{pad: newPaddingFunc(uint(b1.BlockSize())), b1: b1, b2: b2, b3: b3, size: size}
}
func (m *macDES) Size() int {
return m.size
}
func (m *macDES) MAC(src []byte) []byte {
src = m.pad.Pad(src)
blockSize := m.b1.BlockSize()
tag := make([]byte, blockSize)
copy(tag, src[:blockSize])
m.b1.Encrypt(tag, tag)
m.b3.Encrypt(tag, tag)
src = src[blockSize:]
for len(src) > 0 {
subtle.XORBytes(tag, tag, src[:blockSize])
m.b1.Encrypt(tag, tag)
src = src[blockSize:]
}
m.b2.Encrypt(tag, tag)
return tag[:m.size]
}
type cmac struct {
b cipher.Block
k1, k2 []byte
size int
blockSize int
tag []byte
x []byte
nx int
len uint64
}
// NewCMAC returns a CMAC (GB/T 15821.1-2020 MAC scheme 5) instance that implements MAC with the given block cipher.
//
// Reference: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38B.pdf
func NewCMAC(b cipher.Block, size int) *cmac {
if size <= 0 || size > b.BlockSize() {
panic("cbcmac: invalid size")
}
blockSize := b.BlockSize()
k1 := make([]byte, blockSize)
k2 := make([]byte, blockSize)
b.Encrypt(k1, k1)
msb := shiftLeft(k1)
k1[len(k1)-1] ^= msb * 0b10000111
copy(k2, k1)
msb = shiftLeft(k2)
k2[len(k2)-1] ^= msb * 0b10000111
d := &cmac{b: b, k1: k1, k2: k2, size: size}
d.blockSize = blockSize
d.tag = make([]byte, blockSize)
d.x = make([]byte, blockSize)
return d
}
func (c *cmac) Reset() {
for i := range c.tag {
c.tag[i] = 0
}
c.nx = 0
c.len = 0
}
func (c *cmac) BlockSize() int {
return c.blockSize
}
func (c *cmac) Size() int {
return c.size
}
func (d *cmac) Write(p []byte) (nn int, err error) {
nn = len(p)
if nn == 0 {
// nothing to do
return
}
d.len += uint64(nn)
if d.nx == d.blockSize {
// handle remaining full block
d.block(d.x)
d.nx = 0
} else if d.nx > 0 {
// handle remaining incomplete block
n := copy(d.x[d.nx:], p)
d.nx += n
p = p[n:]
if len(p) > 0 {
d.block(d.x)
d.nx = 0
}
}
lenP := len(p)
if lenP > d.blockSize {
n := lenP &^ (d.blockSize - 1)
if n == lenP {
n -= d.blockSize
}
d.block(p[:n])
p = p[n:]
}
// save remaining partial/full block
if len(p) > 0 {
d.nx = copy(d.x, p)
}
return
}
func (c *cmac) block(p []byte) {
for len(p) >= c.blockSize {
subtle.XORBytes(c.tag, p[:c.blockSize], c.tag)
c.b.Encrypt(c.tag, c.tag)
p = p[c.blockSize:]
}
}
// Sum appends the current hash to in and returns the resulting slice.
// It does not change the underlying hash state.
func (d *cmac) Sum(in []byte) []byte {
// Make a copy of d so that caller can keep writing and summing.
// shared block cipher and k1, k2, x
d0 := *d
// use slices.Clone() later
d0.tag = make([]byte, d.blockSize)
copy(d0.tag, d.tag)
hash := d0.checkSum()
return append(in, hash...)
}
func (c *cmac) checkSum() []byte {
tag := make([]byte, c.size)
switch c.nx {
case 0:
// Special-cased as a single empty partial final block.
copy(c.tag, c.k2)
c.tag[0] ^= 0b10000000
case c.blockSize:
subtle.XORBytes(c.tag, c.x, c.tag)
subtle.XORBytes(c.tag, c.k1, c.tag)
default:
subtle.XORBytes(c.tag, c.x, c.tag)
c.tag[c.nx] ^= 0b10000000
subtle.XORBytes(c.tag, c.k2, c.tag)
}
c.b.Encrypt(c.tag, c.tag)
copy(tag, c.tag[:c.size])
return tag
}
func (c *cmac) MAC(src []byte) []byte {
c.Reset()
c.Write(src)
return c.Sum(nil)
}
// shiftLeft sets x to x << 1, and returns MSB₁(x).
func shiftLeft(x []byte) byte {
var msb byte
for i := len(x) - 1; i >= 0; i-- {
msb, x[i] = x[i]>>7, x[i]<<1|msb
}
return msb
}
type lmac struct {
b1, b2 cipher.Block
pad padding.Padding
size int
}
// NewLMAC returns an LMAC (GB/T 15821.1-2020 MAC scheme 6) instance that
// implements MAC with the given block cipher. The padding scheme is ISO/IEC 9797-1 method 2.
func NewLMAC(creator func(key []byte) (cipher.Block, error), key []byte, size int) BlockCipherMAC {
return NewLMACWithPadding(creator, key, size, padding.NewISO9797M2Padding)
}
// NewLMACWithPadding creates a new LMAC (Length-based Message Authentication Code) with padding.
func NewLMACWithPadding(creator func(key []byte) (cipher.Block, error), key []byte, size int, newPaddingFunc padding.NewPaddingFunc) BlockCipherMAC {
var b, b1, b2 cipher.Block
var err error
if b, err = creator(key); err != nil {
panic(err)
}
if size <= 0 || size > b.BlockSize() {
panic("cbcmac: invalid size")
}
blockSize := b.BlockSize()
key1 := make([]byte, blockSize)
key1[blockSize-1] = 0x01
key2 := make([]byte, blockSize)
key2[blockSize-1] = 0x02
b.Encrypt(key1, key1)
b.Encrypt(key2, key2)
if b1, err = creator(key1); err != nil {
panic(err)
}
if b2, err = creator(key2); err != nil {
panic(err)
}
return &lmac{b1: b1, b2: b2, pad: newPaddingFunc(uint(blockSize)), size: size}
}
func (l *lmac) Size() int {
return l.b1.BlockSize()
}
func (l *lmac) MAC(src []byte) []byte {
src = l.pad.Pad(src)
blockSize := l.b1.BlockSize()
tag := make([]byte, blockSize)
for len(src) > blockSize {
subtle.XORBytes(tag, tag, src[:blockSize])
l.b1.Encrypt(tag, tag)
src = src[blockSize:]
}
subtle.XORBytes(tag, tag, src[:blockSize])
l.b2.Encrypt(tag, tag)
return tag
}
type trCBCMAC struct {
b cipher.Block
size int
}
// NewTRCBCMAC returns a TR-CBC-MAC (GB/T 15821.1-2020 MAC scheme 7) instance that
// implements MAC with the given block cipher.
//
// Reference: TrCBC: Another look at CBC-MAC.
func NewTRCBCMAC(b cipher.Block, size int) BlockCipherMAC {
if size <= 0 || size > b.BlockSize() {
panic("cbcmac: invalid size")
}
return &trCBCMAC{b: b, size: size}
}
func (t *trCBCMAC) Size() int {
return t.size
}
func (t *trCBCMAC) MAC(src []byte) []byte {
blockSize := t.b.BlockSize()
tag := make([]byte, blockSize)
padded := false
if len(src) == 0 || len(src)%blockSize != 0 {
pad := padding.NewISO9797M2Padding(uint(blockSize))
src = pad.Pad(src)
padded = true
}
for len(src) > 0 {
subtle.XORBytes(tag, tag, src[:blockSize])
t.b.Encrypt(tag, tag)
src = src[blockSize:]
}
if padded {
return tag[blockSize-t.size:]
}
return tag[:t.size]
}
type cbcrMAC struct {
b cipher.Block
size int
}
// NewCBCRMAC returns a CBCRMAC (GB/T 15821.1-2020 MAC scheme 8) instance that implements MAC with the given block cipher.
//
// Reference: CBCR: CBC MAC with rotating transformations.
func NewCBCRMAC(b cipher.Block, size int) BlockCipherMAC {
if size <= 0 || size > b.BlockSize() {
panic("cbcmac: invalid size")
}
return &cbcrMAC{b: b, size: size}
}
func (c *cbcrMAC) Size() int {
return c.size
}
func (c *cbcrMAC) MAC(src []byte) []byte {
blockSize := c.b.BlockSize()
tag := make([]byte, blockSize)
c.b.Encrypt(tag, tag)
padded := false
if len(src) == 0 || len(src)%blockSize != 0 {
pad := padding.NewISO9797M2Padding(uint(blockSize))
src = pad.Pad(src)
padded = true
}
for len(src) > blockSize {
subtle.XORBytes(tag, tag, src[:blockSize])
c.b.Encrypt(tag, tag)
src = src[blockSize:]
}
subtle.XORBytes(tag, tag, src[:blockSize])
if padded {
shiftLeft(tag)
} else {
shiftRight(tag)
}
c.b.Encrypt(tag, tag)
return tag[:c.size]
}
func shiftRight(x []byte) {
var lsb byte
for i := 0; i < len(x); i++ {
lsb, x[i] = x[i]<<7, x[i]>>1|lsb
}
x[0] ^= lsb
}

791
cbcmac/cbcmac_test.go Normal file
View File

@ -0,0 +1,791 @@
package cbcmac_test
import (
"bytes"
"crypto/aes"
"encoding/hex"
"hash"
"testing"
"github.com/emmansun/gmsm/cbcmac"
"github.com/emmansun/gmsm/internal/cryptotest"
"github.com/emmansun/gmsm/padding"
"github.com/emmansun/gmsm/sm4"
)
func TestCBCMAC(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key []byte
src []byte
tag []byte
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
nil,
[]byte{0x8c, 0x33, 0x8e, 0x5a, 0x27, 0xe3, 0x49, 0xbe, 0xae, 0x39, 0x21, 0x4f, 0xed, 0xa9, 0x70, 0x99},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message for mac"),
[]byte{0x4b, 0x65, 0x53, 0xaf, 0x3c, 0x4e, 0x27, 0x44, 0x84, 0x12, 0x31, 0x5a, 0xc7, 0x84, 0x95, 0x35},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message "),
[]byte{0x42, 0x1a, 0xd1, 0x69, 0x0a, 0xa1, 0x52, 0xe2, 0x84, 0x6f, 0xa2, 0xa5, 0xd8, 0x34, 0x45, 0xa9},
},
}
for i, c := range cases {
block, err := sm4.NewCipher(c.key)
if err != nil {
t.Errorf("#%d: failed to create cipher: %v", i, err)
}
mac := cbcmac.NewCBCMAC(block, len(c.tag))
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestCBCMACWithPadding(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key []byte
src []byte
tag []byte
newPaddingFunc padding.NewPaddingFunc
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
nil,
[]byte{0x8c, 0x33, 0x8e, 0x5a, 0x27, 0xe3, 0x49, 0xbe, 0xae, 0x39, 0x21, 0x4f, 0xed, 0xa9, 0x70, 0x99},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message for mac"),
[]byte{0x4b, 0x65, 0x53, 0xaf, 0x3c, 0x4e, 0x27, 0x44, 0x84, 0x12, 0x31, 0x5a, 0xc7, 0x84, 0x95, 0x35},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message "),
[]byte{0x42, 0x1a, 0xd1, 0x69, 0x0a, 0xa1, 0x52, 0xe2, 0x84, 0x6f, 0xa2, 0xa5, 0xd8, 0x34, 0x45, 0xa9},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message for mac"),
[]byte{0x71, 0xaf, 0x7e, 0x45, 0x53, 0x40, 0x4c, 0xbc, 0xc4, 0xf2, 0x97, 0x3c, 0xdb, 0xd0, 0xf0, 0x63},
padding.NewISO9797M3Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message "),
[]byte{0x6a, 0x4a, 0x86, 0xf5, 0xb5, 0xe4, 0x68, 0xda, 0xd2, 0x7d, 0xf2, 0x5f, 0xb9, 0xd9, 0xbe, 0x16},
padding.NewISO9797M3Padding,
},
}
for i, c := range cases {
block, err := sm4.NewCipher(c.key)
if err != nil {
t.Errorf("#%d: failed to create cipher: %v", i, err)
}
mac := cbcmac.NewCBCMACWithPadding(block, len(c.tag), c.newPaddingFunc)
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestEMACWithPadding(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key1 []byte
key2 []byte
src []byte
tag []byte
newPaddingFunc padding.NewPaddingFunc
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
nil,
[]byte{0x2c, 0xf6, 0xed, 0xf6, 0x3c, 0xce, 0x14, 0x44, 0x89, 0xea, 0xdd, 0xf0, 0x7b, 0x49, 0x38, 0xdb},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message for mac"),
[]byte{0xe4, 0x23, 0xe3, 0x55, 0x99, 0xaf, 0xd9, 0x48, 0xae, 0xc5, 0x0b, 0xde, 0xe8, 0x38, 0xe9, 0xea},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message "),
[]byte{0xf0, 0x26, 0x25, 0xce, 0xad, 0x00, 0x8d, 0x4e, 0xfb, 0xf3, 0xf0, 0xb2, 0xb0, 0xc2, 0xa7, 0x5b},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message for mac"),
[]byte{0x40, 0x03, 0xba, 0x1b, 0x6a, 0xdc, 0x53, 0xa8, 0x26, 0xe8, 0x2f, 0xce, 0xa1, 0x6a, 0xfa, 0xac},
padding.NewISO9797M3Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message "),
[]byte{0xff, 0xd5, 0xf1, 0xf2, 0xe5, 0xed, 0xa5, 0xcb, 0xf4, 0x02, 0xd6, 0x5a, 0x5b, 0x0b, 0x19, 0x53},
padding.NewISO9797M3Padding,
},
}
for i, c := range cases {
mac := cbcmac.NewEMACWithPadding(sm4.NewCipher, c.key1, c.key2, len(c.tag), c.newPaddingFunc)
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestEMAC(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key1 []byte
key2 []byte
src []byte
tag []byte
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
nil,
[]byte{0x2c, 0xf6, 0xed, 0xf6, 0x3c, 0xce, 0x14, 0x44, 0x89, 0xea, 0xdd, 0xf0, 0x7b, 0x49, 0x38, 0xdb},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message for mac"),
[]byte{0xe4, 0x23, 0xe3, 0x55, 0x99, 0xaf, 0xd9, 0x48, 0xae, 0xc5, 0x0b, 0xde, 0xe8, 0x38, 0xe9, 0xea},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message "),
[]byte{0xf0, 0x26, 0x25, 0xce, 0xad, 0x00, 0x8d, 0x4e, 0xfb, 0xf3, 0xf0, 0xb2, 0xb0, 0xc2, 0xa7, 0x5b},
},
}
for i, c := range cases {
mac := cbcmac.NewEMAC(sm4.NewCipher, c.key1, c.key2, len(c.tag))
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestANSIRetailMAC(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key1 []byte
key2 []byte
src []byte
tag []byte
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
nil,
[]byte{0xb4, 0x73, 0x6b, 0xe9, 0xa1, 0x74, 0xfa, 0xa3, 0x4d, 0xb1, 0xe9, 0xf1, 0xda, 0xcd, 0x5d, 0x62},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message for mac"),
[]byte{0x51, 0xe9, 0x92, 0x8c, 0x22, 0x38, 0x33, 0x0c, 0x32, 0x31, 0xb8, 0x75, 0x2a, 0x9a, 0xfd, 0x7f},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message "),
[]byte{0x19, 0x72, 0x47, 0x22, 0x9c, 0xe9, 0xd7, 0xb6, 0xae, 0x40, 0x5b, 0xf8, 0x85, 0xb2, 0x70, 0x57},
},
}
for i, c := range cases {
mac := cbcmac.NewANSIRetailMAC(sm4.NewCipher, c.key1, c.key2, len(c.tag))
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestANSIRetailMACWithPadding(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key1 []byte
key2 []byte
src []byte
tag []byte
newPaddingFunc padding.NewPaddingFunc
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
nil,
[]byte{0xb4, 0x73, 0x6b, 0xe9, 0xa1, 0x74, 0xfa, 0xa3, 0x4d, 0xb1, 0xe9, 0xf1, 0xda, 0xcd, 0x5d, 0x62},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message for mac"),
[]byte{0x51, 0xe9, 0x92, 0x8c, 0x22, 0x38, 0x33, 0x0c, 0x32, 0x31, 0xb8, 0x75, 0x2a, 0x9a, 0xfd, 0x7f},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message "),
[]byte{0x19, 0x72, 0x47, 0x22, 0x9c, 0xe9, 0xd7, 0xb6, 0xae, 0x40, 0x5b, 0xf8, 0x85, 0xb2, 0x70, 0x57},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message for mac"),
[]byte{0x7c, 0xd4, 0x8c, 0x42, 0x42, 0xe4, 0x55, 0x75, 0xe5, 0x1a, 0xaf, 0x0d, 0xcc, 0x7a, 0x20, 0x8c},
padding.NewISO9797M3Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message "),
[]byte{0x3c, 0x43, 0x0f, 0x1e, 0xa4, 0x3b, 0x54, 0x0c, 0x68, 0x45, 0x7e, 0x24, 0x9c, 0x46, 0xf1, 0xdb},
padding.NewISO9797M3Padding,
},
}
for i, c := range cases {
mac := cbcmac.NewANSIRetailMACWithPadding(sm4.NewCipher, c.key1, c.key2, len(c.tag), c.newPaddingFunc)
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestMACDES(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key1 []byte
key2 []byte
src []byte
tag []byte
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
nil,
[]byte{0x0c, 0x56, 0x00, 0x96, 0xb6, 0x09, 0xed, 0x0e, 0xaa, 0x39, 0xaf, 0xd6, 0xe2, 0x66, 0x65, 0x11},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message for mac"),
[]byte{0x7e, 0x1a, 0x9a, 0x5e, 0x0e, 0xf0, 0x94, 0x7f, 0x25, 0xcb, 0x94, 0x85, 0x26, 0x1c, 0x98, 0x5c},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message "),
[]byte{0x94, 0x94, 0x76, 0xd3, 0x5f, 0x17, 0x26, 0x1e, 0x1f, 0xb8, 0xc4, 0x39, 0x6d, 0x62, 0xdc, 0x05},
},
}
for i, c := range cases {
mac := cbcmac.NewMACDES(sm4.NewCipher, c.key1, c.key2, 16)
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestMACDESWithPadding(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key1 []byte
key2 []byte
src []byte
tag []byte
newPaddingFunc padding.NewPaddingFunc
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
nil,
[]byte{0x0c, 0x56, 0x00, 0x96, 0xb6, 0x09, 0xed, 0x0e, 0xaa, 0x39, 0xaf, 0xd6, 0xe2, 0x66, 0x65, 0x11},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message for mac"),
[]byte{0x7e, 0x1a, 0x9a, 0x5e, 0x0e, 0xf0, 0x94, 0x7f, 0x25, 0xcb, 0x94, 0x85, 0x26, 0x1c, 0x98, 0x5c},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message "),
[]byte{0x94, 0x94, 0x76, 0xd3, 0x5f, 0x17, 0x26, 0x1e, 0x1f, 0xb8, 0xc4, 0x39, 0x6d, 0x62, 0xdc, 0x05},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message for mac"),
[]byte{0x28, 0xa7, 0x0d, 0x6b, 0xcc, 0xf7, 0x44, 0x22, 0x46, 0x20, 0x58, 0xab, 0xbc, 0x27, 0xf6, 0xae},
padding.NewISO9797M3Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x41, 0x49, 0xd2, 0xad, 0xed, 0x94, 0x56, 0x68, 0x1e, 0xc8, 0xb5, 0x11, 0xd9, 0xe7, 0xee, 0x04},
[]byte("This is the test message "),
[]byte{0xc9, 0xd3, 0x4e, 0x16, 0xc4, 0x9a, 0xb6, 0x43, 0x57, 0xa2, 0x61, 0x8d, 0xeb, 0xd1, 0x03, 0x2f},
padding.NewISO9797M3Padding,
},
}
for i, c := range cases {
mac := cbcmac.NewMACDESWithPadding(sm4.NewCipher, c.key1, c.key2, 16, c.newPaddingFunc)
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestCMAC(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key []byte
src []byte
tag []byte
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
nil,
[]byte{0x29, 0xe1, 0x54, 0x32, 0x2e, 0x5c, 0x7b, 0xd8, 0xee, 0x6a, 0x25, 0xba, 0x54, 0x9b, 0x24, 0xbc},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message for mac"),
[]byte{0x69, 0x2c, 0x43, 0x71, 0x00, 0xf3, 0xb5, 0xee, 0x2b, 0x8a, 0xbc, 0xef, 0x37, 0x3d, 0x99, 0x0c},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message "),
[]byte{0x47, 0x38, 0xa6, 0xc7, 0x60, 0xb2, 0x80, 0xfc, 0x0c, 0x8a, 0x8a, 0xf3, 0x88, 0x6e, 0x9f, 0x5d},
},
}
for i, c := range cases {
block, err := sm4.NewCipher(c.key)
if err != nil {
t.Errorf("#%d: failed to create cipher: %v", i, err)
}
mac := cbcmac.NewCMAC(block, 16)
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestLMAC(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key []byte
src []byte
tag []byte
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
nil,
[]byte{0xcd, 0x7e, 0xd2, 0x79, 0x64, 0xe2, 0x57, 0xc0, 0x77, 0xf0, 0x55, 0xf8, 0xee, 0x38, 0x3c, 0x3f},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message for mac"),
[]byte{0xa0, 0xc4, 0x65, 0xee, 0x58, 0x96, 0x97, 0x2f, 0x83, 0x37, 0xaa, 0x1f, 0x92, 0xc9, 0x9d, 0x10},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message "),
[]byte{0x60, 0xdd, 0x95, 0x5e, 0xd0, 0xca, 0x3d, 0x7a, 0x64, 0x22, 0x71, 0x74, 0xdd, 0x98, 0xdd, 0x81},
},
}
for i, c := range cases {
mac := cbcmac.NewLMAC(sm4.NewCipher, c.key, 16)
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestLMACWithPadding(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key []byte
src []byte
tag []byte
newPaddingFunc padding.NewPaddingFunc
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
nil,
[]byte{0xcd, 0x7e, 0xd2, 0x79, 0x64, 0xe2, 0x57, 0xc0, 0x77, 0xf0, 0x55, 0xf8, 0xee, 0x38, 0x3c, 0x3f},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message for mac"),
[]byte{0xa0, 0xc4, 0x65, 0xee, 0x58, 0x96, 0x97, 0x2f, 0x83, 0x37, 0xaa, 0x1f, 0x92, 0xc9, 0x9d, 0x10},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message "),
[]byte{0x60, 0xdd, 0x95, 0x5e, 0xd0, 0xca, 0x3d, 0x7a, 0x64, 0x22, 0x71, 0x74, 0xdd, 0x98, 0xdd, 0x81},
padding.NewISO9797M2Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message for mac"),
[]byte{0x43, 0x05, 0x0d, 0x51, 0xc6, 0x56, 0xae, 0x60, 0xbe, 0x27, 0x3f, 0xbe, 0xa4, 0x87, 0x0e, 0xf1},
padding.NewISO9797M3Padding,
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message "),
[]byte{0x61, 0xe0, 0x00, 0x49, 0xe2, 0x69, 0x62, 0xa3, 0x6f, 0xed, 0xba, 0x8d, 0x4f, 0x52, 0xf0, 0xad},
padding.NewISO9797M3Padding,
},
}
for i, c := range cases {
mac := cbcmac.NewLMACWithPadding(sm4.NewCipher, c.key, 16, c.newPaddingFunc)
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestTRCBCMAC(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key []byte
src []byte
tag []byte
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
nil,
[]byte{0xae, 0x39, 0x21, 0x4f, 0xed, 0xa9, 0x70, 0x99},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message for mac"),
[]byte{0x16, 0xe0, 0x29, 0x04, 0xef, 0xb7, 0x65, 0xb7},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message "),
[]byte{0x84, 0x6f, 0xa2, 0xa5, 0xd8, 0x34, 0x45, 0xa9},
},
}
for i, c := range cases {
block, err := sm4.NewCipher(c.key)
if err != nil {
t.Errorf("#%d: failed to create cipher: %v", i, err)
}
mac := cbcmac.NewTRCBCMAC(block, len(c.tag))
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestCBCRMAC(t *testing.T) {
// Test vectors from GB/T 15821.1-2020 Appendix B.
cases := []struct {
key []byte
src []byte
tag []byte
}{
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
nil,
[]byte{0x90, 0x9f, 0x5e, 0x6e, 0xd1, 0x55, 0x18, 0xc0, 0x12, 0x52, 0x30, 0x23, 0x83, 0xc6, 0x3e, 0x8c},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message for mac"),
[]byte{0xe4, 0x0e, 0xd7, 0x9c, 0x31, 0x49, 0xa1, 0xc9, 0xd4, 0x2f, 0x04, 0xc4, 0x23, 0x04, 0x99, 0x35},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte("This is the test message "),
[]byte{0xa9, 0x9d, 0x13, 0x01, 0x3e, 0x89, 0x2e, 0xe2, 0xc2, 0x5b, 0xe2, 0xda, 0xaa, 0x6c, 0x82, 0xe8},
},
}
for i, c := range cases {
block, err := sm4.NewCipher(c.key)
if err != nil {
t.Errorf("#%d: failed to create cipher: %v", i, err)
}
mac := cbcmac.NewCBCRMAC(block, 16)
tag := mac.MAC(c.src)
if !bytes.Equal(tag, c.tag) {
t.Errorf("#%d: expect tag %x, got %x", i, c.tag, tag)
}
}
}
func TestMustPanic(t *testing.T) {
t.Run("invalid size", func(t *testing.T) {
key := make([]byte, 16)
block, _ := sm4.NewCipher(key)
cryptotest.MustPanic(t, "cbcmac: invalid size", func() {
cbcmac.NewCBCMAC(block, 0)
cbcmac.NewCBCMAC(block, 17)
cbcmac.NewEMAC(sm4.NewCipher, key, key, 0)
cbcmac.NewEMAC(sm4.NewCipher, key, key, 17)
cbcmac.NewANSIRetailMAC(sm4.NewCipher, key, key, 0)
cbcmac.NewANSIRetailMAC(sm4.NewCipher, key, key, 17)
cbcmac.NewMACDES(sm4.NewCipher, key, key, 0)
cbcmac.NewMACDES(sm4.NewCipher, key, key, 17)
cbcmac.NewCMAC(block, 0)
cbcmac.NewCMAC(block, 17)
cbcmac.NewLMAC(sm4.NewCipher, key, 0)
cbcmac.NewLMAC(sm4.NewCipher, key, 17)
cbcmac.NewTRCBCMAC(block, 0)
cbcmac.NewTRCBCMAC(block, 17)
cbcmac.NewCBCRMAC(block, 0)
cbcmac.NewCBCRMAC(block, 17)
})
})
t.Run("invalid key size", func(t *testing.T) {
key := make([]byte, 16)
cryptotest.MustPanic(t, "cbcmac: invalid size", func() {
cbcmac.NewEMAC(sm4.NewCipher, key[:15], key, 8)
cbcmac.NewEMAC(sm4.NewCipher, key, key[:15], 8)
cbcmac.NewANSIRetailMAC(sm4.NewCipher, key[:15], key, 8)
cbcmac.NewANSIRetailMAC(sm4.NewCipher, key, key[:15], 8)
cbcmac.NewMACDES(sm4.NewCipher, key[:15], key, 8)
cbcmac.NewMACDES(sm4.NewCipher, key, key[:15], 8)
cbcmac.NewLMAC(sm4.NewCipher, key[:15], 8)
})
})
}
func fromHex(s string) []byte {
b, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return b
}
// Test vectors for CMAC-AES from NIST
// http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf
// Appendix D
var testVectors = []struct {
key, msg, hash string
tagsize int
}{
// AES-128 vectors
{
key: "2b7e151628aed2a6abf7158809cf4f3c",
msg: "",
hash: "bb1d6929e95937287fa37d129b756746",
tagsize: 16,
},
{
key: "2b7e151628aed2a6abf7158809cf4f3c",
msg: "6bc1bee22e409f96e93d7e117393172a",
hash: "070a16b46b4d4144f79bdd9dd04a287c",
tagsize: 16,
},
{
key: "2b7e151628aed2a6abf7158809cf4f3c",
msg: "6bc1bee22e409f96e93d7e117393172aae2d8a57",
hash: "7d85449ea6ea19c823a7bf78837dfade",
tagsize: 16,
},
{
key: "2b7e151628aed2a6abf7158809cf4f3c",
msg: "6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710",
hash: "51f0bebf7e3b9d92fc49741779363cfe",
tagsize: 16,
},
{
key: "2b7e151628aed2a6abf7158809cf4f3c",
msg: "6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411",
hash: "dfa66747de9ae63030ca32611497c827",
tagsize: 16,
},
{
key: "2b7e151628aed2a6abf7158809cf4f3c",
msg: "6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411",
hash: "dfa66747de9ae63030ca32611497c827",
tagsize: 16,
},
{
key: "2b7e151628aed2a6abf7158809cf4f3c",
msg: "6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411",
hash: "dfa66747de9ae63030ca3261",
tagsize: 12,
},
// AES-256 vectors
{
key: "603deb1015ca71be2b73aef0857d7781" +
"1f352c073b6108d72d9810a30914dff4",
msg: "",
hash: "028962f61b7bf89efc6b551f4667d983",
tagsize: 16,
},
{
key: "603deb1015ca71be2b73aef0857d7781" +
"1f352c073b6108d72d9810a30914dff4",
msg: "6bc1bee22e409f96e93d7e117393172a",
hash: "28a7023f452e8f82bd4bf28d8c37c35c",
tagsize: 16,
},
{
key: "603deb1015ca71be2b73aef0857d7781" +
"1f352c073b6108d72d9810a30914dff4",
msg: "6bc1bee22e409f96e93d7e117393172aae2d8a57",
hash: "156727dc0878944a023c1fe03bad6d93",
tagsize: 16,
},
{
key: "603deb1015ca71be2b73aef0857d7781" +
"1f352c073b6108d72d9810a30914dff4",
msg: "6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710",
hash: "e1992190549f6ed5696a2c056c315410",
tagsize: 16,
},
{
key: "603deb1015ca71be2b73aef0857d7781" +
"1f352c073b6108d72d9810a30914dff4",
msg: "6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411",
hash: "aaf3d8f1de5640c232f5b169b9c911e6",
tagsize: 16,
},
{
key: "603deb1015ca71be2b73aef0857d7781" +
"1f352c073b6108d72d9810a30914dff4",
msg: "6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411",
hash: "aaf3d8f1de5640c232f5b169",
tagsize: 12,
},
}
func TestCMACAES(t *testing.T) {
for i, v := range testVectors {
key := fromHex(v.key)
msg := fromHex(v.msg)
hash := fromHex(v.hash)
block, err := aes.NewCipher(key)
if err != nil {
t.Errorf("#%d: failed to create cipher: %v", i, err)
}
mac := cbcmac.NewCMAC(block, v.tagsize)
tag := mac.MAC(msg)
if !bytes.Equal(tag, hash) {
t.Errorf("#%d: expect tag %x, got %x", i, hash, tag)
}
}
}
func TestCMACHash(t *testing.T) {
t.Run("CMAC Hash", func(t *testing.T) {
cryptotest.TestHash(t, func() hash.Hash {
key := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}
block, err := aes.NewCipher(key)
if err != nil {
t.Fatal(err)
}
return cbcmac.NewCMAC(block, 16)
})
})
}
var buf = make([]byte, 8192)
func benchmarkSize(hash hash.Hash, b *testing.B, size int) {
b.SetBytes(int64(size))
sum := make([]byte, hash.Size())
for i := 0; i < b.N; i++ {
hash.Reset()
hash.Write(buf[:size])
hash.Sum(sum[:0])
}
}
func BenchmarkAESCMAC1K(b *testing.B) {
key := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}
block, err := aes.NewCipher(key)
if err != nil {
b.Fatal(err)
}
benchmarkSize(cbcmac.NewCMAC(block, 16), b, 1024)
}
func BenchmarkSM4CMAC1K(b *testing.B) {
key := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}
block, err := sm4.NewCipher(key)
if err != nil {
b.Fatal(err)
}
benchmarkSize(cbcmac.NewCMAC(block, 16), b, 1024)
}

57
cfca/encrypt.go Normal file
View File

@ -0,0 +1,57 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cfca
import (
"crypto/cipher"
"errors"
"github.com/emmansun/gmsm/padding"
"github.com/emmansun/gmsm/sm3"
"github.com/emmansun/gmsm/sm4"
)
// NewSM4CBCBlockMode creates a new SM4-CBC block mode with the password.
func NewSM4CBCBlockMode(password []byte, isEncrypter bool) (cipher.BlockMode, error) {
if len(password) == 0 {
return nil, errors.New("cfca: invalid password")
}
ivkey := sm3.Kdf(password, 32)
block, err := sm4.NewCipher(ivkey[16:])
if err != nil {
return nil, err
}
if isEncrypter {
return cipher.NewCBCEncrypter(block, ivkey[:16]), nil
}
return cipher.NewCBCDecrypter(block, ivkey[:16]), nil
}
// EncryptBySM4CBC encrypts the data with the password using SM4-CBC algorithm.
// Corresponds to the cfca.sadk.util.encryptMessageBySM4 method.
func EncryptBySM4CBC(plaintext, password []byte) ([]byte, error) {
mode, err := NewSM4CBCBlockMode(password, true)
if err != nil {
return nil, err
}
pkcs7 := padding.NewPKCS7Padding(uint(mode.BlockSize()))
plaintext = pkcs7.Pad(plaintext)
ciphertext := make([]byte, len(plaintext))
mode.CryptBlocks(ciphertext, plaintext)
return ciphertext, nil
}
// DecryptBySM4CBC decrypts the data with the password using SM4-CBC algorithm.
// Corresponds to the cfca.sadk.util.decryptMessageBySM4 method.
func DecryptBySM4CBC(ciphertext, password []byte) ([]byte, error) {
mode, err := NewSM4CBCBlockMode(password, false)
if err != nil {
return nil, err
}
plaintext := make([]byte, len(ciphertext))
mode.CryptBlocks(plaintext, ciphertext)
pkcs7 := padding.NewPKCS7Padding(uint(mode.BlockSize()))
return pkcs7.Unpad(plaintext)
}

180
cfca/example_test.go Normal file
View File

@ -0,0 +1,180 @@
package cfca_test
import (
"crypto/ecdsa"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/hex"
"encoding/pem"
"fmt"
"github.com/emmansun/gmsm/cfca"
"github.com/emmansun/gmsm/sm2"
)
func ExampleParseSM2() {
base64data := `
MIIDSQIBATBHBgoqgRzPVQYBBAIBBgcqgRzPVQFoBDDkLvKllj9ZWhaKU6MSnxBBV5yaF3tEcOk1
vQniWyVzyaQA4F3j/YvDJwEoE8gOF/swggL5BgoqgRzPVQYBBAIBBIIC6TCCAuUwggKJoAMCAQIC
BRBAmQgJMAwGCCqBHM9VAYN1BQAwXDELMAkGA1UEBhMCQ04xMDAuBgNVBAoMJ0NoaW5hIEZpbmFu
Y2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEbMBkGA1UEAwwSQ0ZDQSBURVNUIFNNMiBPQ0Ex
MB4XDTIwMTExOTA4MzExOFoXDTI1MTExOTA4MzExOFowgYkxCzAJBgNVBAYTAkNOMRcwFQYDVQQK
DA5DRkNBIFRFU1QgT0NBMTENMAsGA1UECwwEUFNCQzEZMBcGA1UECwwQT3JnYW5pemF0aW9uYWwt
MjE3MDUGA1UEAwwuMDUxQOmCruWCqOe6v+S4iuaUtuWNleWVhuaIt0BONTEwMTEzMDAwMTg4NzhA
MTBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABJVRC63OKfcL4H324rDOdb4SSlbAjoJDXnK0qmwX
Z59FWmiSqt3ipreljKew4QynjTgR/yfp9yjNgNU8G5pkYdujggEGMIIBAjAfBgNVHSMEGDAWgBRr
/hjaj0I6prhtsy6Igzo0osEw4TAMBgNVHRMBAf8EAjAAMEgGA1UdIARBMD8wPQYIYIEchu8qAQEw
MTAvBggrBgEFBQcCARYjaHR0cDovL3d3dy5jZmNhLmNvbS5jbi91cy91cy0xNC5odG0wOQYDVR0f
BDIwMDAuoCygKoYoaHR0cDovL3VjcmwuY2ZjYS5jb20uY24vU00yL2NybDE0MzU2LmNybDAOBgNV
HQ8BAf8EBAMCBsAwHQYDVR0OBBYEFPiGPZT0oTuRXvkyGoOgviNEWnc1MB0GA1UdJQQWMBQGCCsG
AQUFBwMCBggrBgEFBQcDBDAMBggqgRzPVQGDdQUAA0gAMEUCIQCJDSsVPfhr+gnDASMj5Syt+hxs
amHygPecjCLbcdFQQgIgSXC4musF5Fnj/CpNTqvk9+56FuINkATGS8xRh7kzKBE=`
password := []byte("123456")
data, err := base64.StdEncoding.DecodeString(base64data)
if err != nil {
panic(err)
}
priv, cert, err := cfca.ParseSM2(password, data)
if err != nil {
panic(err)
}
fmt.Printf("%x\n", priv.D.Bytes())
fmt.Printf("%v\n", cert.Issuer)
// Output: d3f24d61bb2816882b8474b778dd7c3166d665f9455dc9d551c989c161e76ab0
// CN=CFCA TEST SM2 OCA1,O=China Financial Certification Authority,C=CN
}
func ExampleParseSM2_pemEncoded() {
pemdata := `
-----BEGIN CFCA KEY-----
MIIDSQIBATBHBgoqgRzPVQYBBAIBBgcqgRzPVQFoBDDkLvKllj9ZWhaKU6MSnxBBV5yaF3tEcOk1
vQniWyVzyaQA4F3j/YvDJwEoE8gOF/swggL5BgoqgRzPVQYBBAIBBIIC6TCCAuUwggKJoAMCAQIC
BRBAmQgJMAwGCCqBHM9VAYN1BQAwXDELMAkGA1UEBhMCQ04xMDAuBgNVBAoMJ0NoaW5hIEZpbmFu
Y2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEbMBkGA1UEAwwSQ0ZDQSBURVNUIFNNMiBPQ0Ex
MB4XDTIwMTExOTA4MzExOFoXDTI1MTExOTA4MzExOFowgYkxCzAJBgNVBAYTAkNOMRcwFQYDVQQK
DA5DRkNBIFRFU1QgT0NBMTENMAsGA1UECwwEUFNCQzEZMBcGA1UECwwQT3JnYW5pemF0aW9uYWwt
MjE3MDUGA1UEAwwuMDUxQOmCruWCqOe6v+S4iuaUtuWNleWVhuaIt0BONTEwMTEzMDAwMTg4NzhA
MTBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABJVRC63OKfcL4H324rDOdb4SSlbAjoJDXnK0qmwX
Z59FWmiSqt3ipreljKew4QynjTgR/yfp9yjNgNU8G5pkYdujggEGMIIBAjAfBgNVHSMEGDAWgBRr
/hjaj0I6prhtsy6Igzo0osEw4TAMBgNVHRMBAf8EAjAAMEgGA1UdIARBMD8wPQYIYIEchu8qAQEw
MTAvBggrBgEFBQcCARYjaHR0cDovL3d3dy5jZmNhLmNvbS5jbi91cy91cy0xNC5odG0wOQYDVR0f
BDIwMDAuoCygKoYoaHR0cDovL3VjcmwuY2ZjYS5jb20uY24vU00yL2NybDE0MzU2LmNybDAOBgNV
HQ8BAf8EBAMCBsAwHQYDVR0OBBYEFPiGPZT0oTuRXvkyGoOgviNEWnc1MB0GA1UdJQQWMBQGCCsG
AQUFBwMCBggrBgEFBQcDBDAMBggqgRzPVQGDdQUAA0gAMEUCIQCJDSsVPfhr+gnDASMj5Syt+hxs
amHygPecjCLbcdFQQgIgSXC4musF5Fnj/CpNTqvk9+56FuINkATGS8xRh7kzKBE=
-----END CFCA KEY-----`
password := []byte("123456")
block, _ := pem.Decode([]byte(pemdata))
if block == nil {
panic("failed to decode PEM block")
}
priv, cert, err := cfca.ParseSM2(password, block.Bytes)
if err != nil {
panic(err)
}
fmt.Printf("%x\n", priv.D.Bytes())
fmt.Printf("%v\n", cert.Issuer)
// Output: d3f24d61bb2816882b8474b778dd7c3166d665f9455dc9d551c989c161e76ab0
// CN=CFCA TEST SM2 OCA1,O=China Financial Certification Authority,C=CN
}
func ExampleMarshalSM2_changePassword() {
pemdata := `
-----BEGIN CFCA KEY-----
MIIDSQIBATBHBgoqgRzPVQYBBAIBBgcqgRzPVQFoBDDkLvKllj9ZWhaKU6MSnxBBV5yaF3tEcOk1
vQniWyVzyaQA4F3j/YvDJwEoE8gOF/swggL5BgoqgRzPVQYBBAIBBIIC6TCCAuUwggKJoAMCAQIC
BRBAmQgJMAwGCCqBHM9VAYN1BQAwXDELMAkGA1UEBhMCQ04xMDAuBgNVBAoMJ0NoaW5hIEZpbmFu
Y2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEbMBkGA1UEAwwSQ0ZDQSBURVNUIFNNMiBPQ0Ex
MB4XDTIwMTExOTA4MzExOFoXDTI1MTExOTA4MzExOFowgYkxCzAJBgNVBAYTAkNOMRcwFQYDVQQK
DA5DRkNBIFRFU1QgT0NBMTENMAsGA1UECwwEUFNCQzEZMBcGA1UECwwQT3JnYW5pemF0aW9uYWwt
MjE3MDUGA1UEAwwuMDUxQOmCruWCqOe6v+S4iuaUtuWNleWVhuaIt0BONTEwMTEzMDAwMTg4NzhA
MTBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABJVRC63OKfcL4H324rDOdb4SSlbAjoJDXnK0qmwX
Z59FWmiSqt3ipreljKew4QynjTgR/yfp9yjNgNU8G5pkYdujggEGMIIBAjAfBgNVHSMEGDAWgBRr
/hjaj0I6prhtsy6Igzo0osEw4TAMBgNVHRMBAf8EAjAAMEgGA1UdIARBMD8wPQYIYIEchu8qAQEw
MTAvBggrBgEFBQcCARYjaHR0cDovL3d3dy5jZmNhLmNvbS5jbi91cy91cy0xNC5odG0wOQYDVR0f
BDIwMDAuoCygKoYoaHR0cDovL3VjcmwuY2ZjYS5jb20uY24vU00yL2NybDE0MzU2LmNybDAOBgNV
HQ8BAf8EBAMCBsAwHQYDVR0OBBYEFPiGPZT0oTuRXvkyGoOgviNEWnc1MB0GA1UdJQQWMBQGCCsG
AQUFBwMCBggrBgEFBQcDBDAMBggqgRzPVQGDdQUAA0gAMEUCIQCJDSsVPfhr+gnDASMj5Syt+hxs
amHygPecjCLbcdFQQgIgSXC4musF5Fnj/CpNTqvk9+56FuINkATGS8xRh7kzKBE=
-----END CFCA KEY-----`
password := []byte("123456")
block, _ := pem.Decode([]byte(pemdata))
if block == nil {
panic("failed to decode PEM block")
}
priv, cert, err := cfca.ParseSM2(password, block.Bytes)
if err != nil {
panic(err)
}
newpassword := []byte("654321")
data, err := cfca.MarshalSM2(newpassword, priv, cert)
if err != nil {
panic(err)
}
priv2, cert2, err := cfca.ParseSM2(newpassword, data)
if err != nil {
panic(err)
}
fmt.Printf("%x\n", priv2.D.Bytes())
fmt.Printf("%v\n", cert2.Issuer)
// Output: d3f24d61bb2816882b8474b778dd7c3166d665f9455dc9d551c989c161e76ab0
// CN=CFCA TEST SM2 OCA1,O=China Financial Certification Authority,C=CN
}
func ExampleCreateCertificateRequest() {
keyBytes, _ := hex.DecodeString("6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85")
priv, err := sm2.NewPrivateKey(keyBytes)
if err != nil {
panic(err)
}
random := rand.Reader
// tmpKey used to decrypt the returned escrow PrivateKey
keyBytes, _ = hex.DecodeString("cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba")
tmpKey, err := sm2.NewPrivateKey(keyBytes)
if err != nil {
panic(err)
}
template := &x509.CertificateRequest{
Subject: pkix.Name{
CommonName: "certRequisition",
Organization: []string{"CFCA TEST CA"},
Country: []string{"CN"},
},
}
csrder, err := cfca.CreateCertificateRequest(random, template, priv, &tmpKey.PublicKey, "123456")
if err != nil {
panic(err)
}
// you can encode the csrder to PEM format or base64 format
csr, err := cfca.ParseCertificateRequest(csrder)
if err != nil {
panic(err)
}
fmt.Printf("%v\n", csr.Subject)
fmt.Printf("%v\n", csr.ChallengePassword)
fmt.Printf("%x\n", csr.TmpPublicKey.(*ecdsa.PublicKey).X)
// Output: CN=certRequisition,O=CFCA TEST CA,C=CN
// 123456
// c7c4d0945ebdfc2111ad64b0e92e04582b0725fea172968c6c40162c810f8882
}
func ExampleParseEscrowPrivateKey() {
// a sample method to parse the escrow private key
keydata := `00000000000000010000000000000001000000000000000000000000000000000000000000000268MIHGAgEBBIHArhtKwTVT8dPEkykVRpvQNMxHv/yeqtaKZiSp2MbjcqMZtPfKW8IatiIPPitNhQtU5C7gMbsUxgf5Yo16vDSXdoWqoOOaes2pEJwmXWZI55lMMWc168WgzQ82fmMi05Vhlw9HNjGI3azE6MS5/ujSNGLZ0qAAmLnBiHlXFAXXAWRiy9MxZKwF4xKn6qMaKmkqbYmTbBbEJEhzJBmu0IJ1kNDcTFirAyapghHSw267erSUwsHjkQis9mKYpzGied0E`
keyBytes, _ := hex.DecodeString("cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba")
tmpKey, err := sm2.NewPrivateKey(keyBytes)
if err != nil {
panic(err)
}
encKey, err := cfca.ParseEscrowPrivateKey(tmpKey, []byte(keydata))
if err != nil {
panic(err)
}
fmt.Printf("%x\n", encKey.D.Bytes())
// Output: f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b
}

92
cfca/pkcs10.go Normal file
View File

@ -0,0 +1,92 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cfca
import (
"bytes"
"crypto/ecdsa"
"crypto/x509"
"encoding/asn1"
"encoding/base64"
"errors"
"io"
"strconv"
"github.com/emmansun/gmsm/sm2"
"github.com/emmansun/gmsm/smx509"
)
type CertificateRequest = smx509.CertificateRequestCFCA
// CreateCertificateRequest creates a new certificate request based on a template.
// The following members of template are used: Subject.
// The certPriv is the private key for the certificate, and the tmpPub is the temporary public key for returning encryption key decryption.
// The challenge password is basically a shared-secret nonce between you and CFCA, embedded in the CSR.
func CreateCertificateRequest(rand io.Reader, template *x509.CertificateRequest, certPriv, tmpPub any, challengePassword string) ([]byte, error) {
return smx509.CreateCFCACertificateRequest(rand, template, certPriv, tmpPub, challengePassword)
}
// ParseCertificateRequest parses a certificate request from the given DER data.
// This method corresponds to CFCA SADK's cfca.sadk.asn1.pkcs.PKCS10.load.
func ParseCertificateRequest(der []byte) (*CertificateRequest, error) {
return smx509.ParseCFCACertificateRequest(der)
}
const encryptedEncKeyPrefix = "0000000000000001000000000000000100000000000000000000000000000000"
type encryptedPrivateKeyInfo struct {
Version int `asn1:"default:1"`
EncryptedKey []byte
}
// ParseEscrowPrivateKey parses an CFCA generated and returned SM2 private key from the given data.
// The data is expected to be in the format of "0000000000000001000000000000000100000000000000000000000000000000...".
// If the data is not in this format, it will be treated as base64 encoded data directly.
func ParseEscrowPrivateKey(tmpPriv *sm2.PrivateKey, data []byte) (*sm2.PrivateKey, error) {
if len(data) < 268 {
return nil, errors.New("cfca: invalid encrypted private key data")
}
encodedKeyPart := data
if bytes.HasPrefix(data, []byte(encryptedEncKeyPrefix)) {
retLen, err := strconv.Atoi(string(data[64:80]))
if err != nil {
return nil, err
}
if retLen != len(data[80:]) {
return nil, errors.New("cfca: invalid encrypted private key data")
}
encodedKeyPart = data[80:]
}
// remove all commas ONLY now. If there are other non-base64 characters, the base64 decoder will fail.
encodedKeyPart = bytes.ReplaceAll(encodedKeyPart, []byte{44}, []byte{})
der, err := base64.StdEncoding.DecodeString(string(encodedKeyPart))
if err != nil {
return nil, err
}
var keyInfo encryptedPrivateKeyInfo
if _, err := asn1.Unmarshal(der, &keyInfo); err != nil {
return nil, err
}
var ret []byte
if ret, err = tmpPriv.Decrypt(nil, append([]byte{0x04}, keyInfo.EncryptedKey...), nil); err != nil {
return nil, errors.New("cfca: failed to decrypt the private key, possibly due to incorrect key data")
}
// X || Y || D
if len(ret) != 96 {
return nil, errors.New("cfca: invalid decrypted private key data")
}
var priv *sm2.PrivateKey
if priv, err = sm2.NewPrivateKey(ret[64:]); err != nil {
return nil, err
}
var pub *ecdsa.PublicKey
if pub, err = sm2.NewPublicKey(append([]byte{0x04}, ret[:64]...)); err != nil {
return nil, err
}
if !pub.Equal(&priv.PublicKey) {
return nil, errors.New("cfca: key pair mismatch, possibly due to incorrect key data or corruption")
}
return priv, nil
}

281
cfca/pkcs10_test.go Normal file
View File

@ -0,0 +1,281 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cfca
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/hex"
"testing"
"github.com/emmansun/gmsm/sm2"
)
func TestCreateCertificateRequest(t *testing.T) {
random := rand.Reader
certKey, err := sm2.GenerateKey(random)
if err != nil {
t.Fatal(err)
}
certRSAKey, err := rsa.GenerateKey(random, 2048)
if err != nil {
t.Fatal(err)
}
tmpKey, err := sm2.GenerateKey(random)
if err != nil {
t.Fatal(err)
}
p256Key, err := ecdsa.GenerateKey(elliptic.P256(), random)
if err != nil {
t.Fatal(err)
}
rsaKey, err := rsa.GenerateKey(random, 2048)
if err != nil {
t.Fatal(err)
}
template := &x509.CertificateRequest{
Subject: pkix.Name{
CommonName: "certRequisition",
Organization: []string{"CFCA TEST CA"},
Country: []string{"CN"},
},
}
testCases := []struct {
template *x509.CertificateRequest
priv interface{}
tmpPub interface{}
challengePassword string
wantErr bool
errormsg string
}{
{
template: template,
priv: certKey,
tmpPub: tmpKey.Public(),
challengePassword: "111111",
wantErr: false,
errormsg: "",
},
{
template: template,
priv: certRSAKey,
tmpPub: rsaKey.Public(),
challengePassword: "111111",
wantErr: false,
errormsg: "",
},
{
template: template,
priv: p256Key,
tmpPub: nil,
challengePassword: "",
wantErr: false,
errormsg: "",
},
{
template: template,
priv: "",
tmpPub: "",
challengePassword: "",
wantErr: true,
errormsg: "x509: certificate private key does not implement crypto.Signer",
},
{
template: template,
priv: certKey,
tmpPub: "",
challengePassword: "",
wantErr: true,
errormsg: "x509: SM2 temp public key is required",
},
{
template: template,
priv: certKey,
tmpPub: rsaKey.Public(),
challengePassword: "",
wantErr: true,
errormsg: "x509: SM2 temp public key is required",
},
{
template: template,
priv: certRSAKey,
tmpPub: tmpKey.Public(),
challengePassword: "",
wantErr: true,
errormsg: "x509: RSA temp public key is required",
},
{
template: template,
priv: certKey,
tmpPub: p256Key.Public(),
challengePassword: "",
wantErr: true,
errormsg: "x509: SM2 temp public key is required",
},
{
template: template,
priv: p256Key,
tmpPub: certKey.Public(),
challengePassword: "111111",
wantErr: true,
errormsg: "x509: only RSA or SM2 key is supported",
},
{
template: template,
priv: certKey,
tmpPub: tmpKey.Public(),
challengePassword: "",
wantErr: true,
errormsg: "x509: challenge password is required",
},
}
for _, tc := range testCases {
_, err := CreateCertificateRequest(random, tc.template, tc.priv, tc.tmpPub, tc.challengePassword)
if tc.wantErr {
if err == nil {
t.Fatal("expected error, got nil")
}
if err.Error() != tc.errormsg {
t.Fatalf("expected error %s, got %s", tc.errormsg, err.Error())
}
} else if err != nil {
t.Fatal(err)
}
}
}
func TestParseEscrowPrivateKey(t *testing.T) {
cases := []struct {
encKeyHex string
tmpKeyHex string
encryptedKey string
wantError bool
errorMsg string
}{
{ // with prefix, without delimiter
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"00000000000000010000000000000001000000000000000000000000000000000000000000000268MIHGAgEBBIHArhtKwTVT8dPEkykVRpvQNMxHv/yeqtaKZiSp2MbjcqMZtPfKW8IatiIPPitNhQtU5C7gMbsUxgf5Yo16vDSXdoWqoOOaes2pEJwmXWZI55lMMWc168WgzQ82fmMi05Vhlw9HNjGI3azE6MS5/ujSNGLZ0qAAmLnBiHlXFAXXAWRiy9MxZKwF4xKn6qMaKmkqbYmTbBbEJEhzJBmu0IJ1kNDcTFirAyapghHSw267erSUwsHjkQis9mKYpzGied0E",
false,
"",
},
{ // without prefix, without delimiter
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"MIHGAgEBBIHArhtKwTVT8dPEkykVRpvQNMxHv/yeqtaKZiSp2MbjcqMZtPfKW8IatiIPPitNhQtU5C7gMbsUxgf5Yo16vDSXdoWqoOOaes2pEJwmXWZI55lMMWc168WgzQ82fmMi05Vhlw9HNjGI3azE6MS5/ujSNGLZ0qAAmLnBiHlXFAXXAWRiy9MxZKwF4xKn6qMaKmkqbYmTbBbEJEhzJBmu0IJ1kNDcTFirAyapghHSw267erSUwsHjkQis9mKYpzGied0E",
false,
"",
},
{ // with prefix, with delimiter
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"00000000000000010000000000000001000000000000000000000000000000000000000000000273MIHGAgEBBIHArhtKwTVT8dPEkykVRpvQNMxHv/yeqtaKZiSp2MbjcqMZtPfKW8Ia,tiIPPitNhQtU5C7gMbsUxgf5Yo16vDSXdoWqoOOaes2pEJwmXWZI55lMMWc168Wg,zQ82fmMi05Vhlw9HNjGI3azE6MS5/ujSNGLZ0qAAmLnBiHlXFAXXAWRiy9MxZKwF,4xKn6qMaKmkqbYmTbBbEJEhzJBmu0IJ1kNDcTFirAyapghHSw267erSUwsHjkQis,9mKYpzGied0E,",
false,
"",
},
{ // too short
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"000000000000000100000000000000010",
true,
"cfca: invalid encrypted private key data",
},
{ // length not match
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"00000000000000010000000000000001000000000000000000000000000000000000000000000273MIHGAgEBBIHArhtKwTVT8dPEkykVRpvQNMxHv/yeqtaKZiSp2MbjcqMZtPfKW8IatiIPPitNhQtU5C7gMbsUxgf5Yo16vDSXdoWqoOOaes2pEJwmXWZI55lMMWc168WgzQ82fmMi05Vhlw9HNjGI3azE6MS5/ujSNGLZ0qAAmLnBiHlXFAXXAWRiy9MxZKwF4xKn6qMaKmkqbYmTbBbEJEhzJBmu0IJ1kNDcTFirAyapghHSw267erSUwsHjkQis9mKYpzGied0E",
true,
"cfca: invalid encrypted private key data",
},
{ // with prefix, with invalid delimiter
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"00000000000000010000000000000001000000000000000000000000000000000000000000000274MIHGAgEBBIHArhtKwTVT8dPEkykVRpvQNMxHv/yeqtaKZiSp2MbjcqMZtPfKW8Ia, tiIPPitNhQtU5C7gMbsUxgf5Yo16vDSXdoWqoOOaes2pEJwmXWZI55lMMWc168Wg,zQ82fmMi05Vhlw9HNjGI3azE6MS5/ujSNGLZ0qAAmLnBiHlXFAXXAWRiy9MxZKwF,4xKn6qMaKmkqbYmTbBbEJEhzJBmu0IJ1kNDcTFirAyapghHSw267erSUwsHjkQis,9mKYpzGied0E,",
true,
"illegal base64 data at input byte 64",
},
{ // invalid base64
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"NIHGAgEBBIHArhtKwTVT8dPEkykVRpvQNMxHv/yeqtaKZiSp2MbjcqMZtPfKW8IatiIPPitNhQtU5C7gMbsUxgf5Yo16vDSXdoWqoOOaes2pEJwmXWZI55lMMWc168WgzQ82fmMi05Vhlw9HNjGI3azE6MS5/ujSNGLZ0qAAmLnBiHlXFAXXAWRiy9MxZKwF4xKn6qMaKmkqbYmTbBbEJEhzJBmu0IJ1kNDcTFirAyapghHSw267erSUwsHjkQis9mKYpzGied0E",
true,
"asn1: structure error: tags don't match (16 vs {class:0 tag:20 length:198 isCompound:true}) {optional:false explicit:false application:false private:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false} encryptedPrivateKeyInfo @3",
},
{ // with prefix, with delimiter, invalid length string
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"00000000000000010000000000000001000000000000000000000000000000000000000000000/73MIHGAgEBBIHArhtKwTVT8dPEkykVRpvQNMxHv/yeqtaKZiSp2MbjcqMZtPfKW8Ia,tiIPPitNhQtU5C7gMbsUxgf5Yo16vDSXdoWqoOOaes2pEJwmXWZI55lMMWc168Wg,zQ82fmMi05Vhlw9HNjGI3azE6MS5/ujSNGLZ0qAAmLnBiHlXFAXXAWRiy9MxZKwF,4xKn6qMaKmkqbYmTbBbEJEhzJBmu0IJ1kNDcTFirAyapghHSw267erSUwsHjkQis,9mKYpzGied0E,",
true,
"strconv.Atoi: parsing \"0000000000000/73\": invalid syntax",
},
{
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"MIHLAgEBBIHFBNMWBxk04B00wJQC1fQsida/0ZZEAMh/ggaC006oQUFFQKJp18YgC/9xkkBLa75DxPy85+n21gZaXUs3s628SaQiKejqH7yx3Pr0onRepDED5O/grQoyxdHL3LpuC4jp7MrOeVDqC6PAWIhZanDhdN4617QJeBmKbkZSqo/SNXfh9+QDDwBBNMLV27LR53ShpAUYbJwqQoW2Od4+MGkzUK3jy+T9HbPcaAZMedAuhXhQgRf69x8CNSHjmOVVFQQZe7OHYY8=",
true,
"cfca: failed to decrypt the private key, possibly due to incorrect key data",
},
{
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"MIHKAgEBBIHEMEiAGc8dn+9mKnIlaesNqV2h53FxzNm1O4Bl5P16t6QT4JcJvTcTsh9DiHZF1Z0b+z/PrAT2r8aST2aKwRBPLrkWHKKDLZnCtAuz3Al1sV5ZMb5dCVX/Gy3LWMhVNwmzgkV6hfuFokTc2qL7p297XG4nnT11jz7iI1sRJ2E7bn52tF6W6ApICJuDKyFiLVKmMayn3PSsd8+I5IXNNtIer+GYKabAkNHwao4cuK1tuhy1uiSlwfzWq1CSHFD+LIRbXpijQA==",
true,
"cfca: invalid decrypted private key data",
},
{
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"MIHGAgEBBIHANZyM9KF7qqyUDzh6wZmLU6czep9FxJfojSpxrAYbNN2j/Jad5cOaNmhO4tL+tfk42O8y9+jUebPWCUOuSXZADJZOEyRo2tehvrT2CxEEA9cJ0pK87uXiRsd9vLyjYeEzbngO8tpFrSrpF8G/KYbJ1QiI3W+QLQnofwtChNVwOjyjLxoFO9gx3jvfVH79ECoYC11UL0o0YASx9niiGkqT/q8tqbr7DwIDu0tbXVfwhjJJ2zNZIdECDkV3o7as9ika",
true,
"sm2: invalid private key",
},
{
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"MIHGAgEBBIHAaxudEYQXAT4n+s2fhHJlPVvY2+TNRAS96F7vskiENVLHahIWxtDeU6BeJ5SFTEXTz5vdYp4as66DU69xCWNYl4kDCy3gfT2iIDEp6NcbPHkAp/rKIFXMUZyBq9wGCkeAZwvpK09JMLffvGWTFU7MzepyFtYTsRjwZ5tBX+8GaSDHaCD0CtVtz5k3bFRLPE2ru4XZW787BiEBrxUG9Zn5pnkNLlnVmUNSI01qKXJxK/hAJ+B82DtXdZgSUaspW5ro",
true,
"point not on SM2 P256 curve",
},
{
"f6e02c941a0dfdac58d8b3b1bc1bd136f179741b7465ebc7b0b25bb381840a3b",
"cacece36cac24aab94e52bcd5c0f552c95028f2856053135a1e47510b4c307ba",
"MIHGAgEBBIHA7pcowvNdY6kHesm6Ni1rM+iFNSXOXyET+gstbxQ0Vq1+W+YmZUTNQs8CpNuU6fpjZt8azXvKwdrUKEMaadZR4vTBwl+UcvjdpwlBmI8o9UxYkWNSGeI0CWHCgml57xHbhAl3xlRzCi2qOakvEcwTRmzvB73Pt/DgahSPGSmdOy3CrAyMkhcrHiiR9aIWXEKbOnwST+wcRJ65Mr+5ZDOaN8wg6NzLttnWg93CA3k1AsziCGe/sRW6Qd2FrcvMZQc2",
true,
"cfca: key pair mismatch, possibly due to incorrect key data or corruption",
},
}
for _, c := range cases {
encKey, _ := hex.DecodeString(c.encKeyHex)
tmpKey, _ := hex.DecodeString(c.tmpKeyHex)
tmpSM2Key, err := sm2.NewPrivateKey(tmpKey)
if err != nil {
t.Fatal(err)
}
targetEncKey, err := sm2.NewPrivateKey(encKey)
if err != nil {
t.Fatal(err)
}
gotKey, err := ParseEscrowPrivateKey(tmpSM2Key, []byte(c.encryptedKey))
if c.wantError {
if err == nil || err.Error() != c.errorMsg {
t.Fatalf("expected error %v, got %v", c.errorMsg, err)
}
continue
}
if err != nil {
t.Fatal(err)
}
if !gotKey.Equal(targetEncKey) {
t.Fatalf("decrypted key not match")
}
}
}

105
cfca/pkcs12_sm2.go Normal file
View File

@ -0,0 +1,105 @@
// Package cfca supports part of CFCA SADK's functions, provides interoperability with CFCA SADK.
package cfca
import (
"encoding/asn1"
"errors"
"fmt"
"math/big"
"github.com/emmansun/gmsm/pkcs"
"github.com/emmansun/gmsm/pkcs7"
"github.com/emmansun/gmsm/sm2"
"github.com/emmansun/gmsm/smx509"
)
// cfcaKeyPairData represents a key pair data structure used
// in CFCA (China Financial Certification Authority)
// for both parsing and marshaling SM2 keys and certificates.
type cfcaKeyPairData struct {
Version int `asn1:"default:1"`
EncryptedKey keyData
Certificate certData
}
// Encrypted private key data
type keyData struct {
ContentType asn1.ObjectIdentifier
Algorithm asn1.ObjectIdentifier
EncryptedContent asn1.RawValue
}
// Corresponding certificate
type certData struct {
ContentType asn1.ObjectIdentifier
Content asn1.RawContent
}
var (
oidSM2Data = pkcs7.SM2OIDData
oidSM4 = pkcs.SM4.OID()
oidSM4CBC = pkcs.SM4CBC.OID()
)
// ParseSM2 parses the der data, returns private key and related certificate, it's CFCA private structure.
// This method is corresponding to CFCA SADK's cfca.sadk.asn1.pkcs.load.
func ParseSM2(password, data []byte) (*sm2.PrivateKey, *smx509.Certificate, error) {
var keys cfcaKeyPairData
if _, err := asn1.Unmarshal(data, &keys); err != nil {
return nil, nil, err
}
if !keys.Certificate.ContentType.Equal(oidSM2Data) {
return nil, nil, fmt.Errorf("cfca: unsupported content type oid <%v>", keys.Certificate.ContentType)
}
if !keys.EncryptedKey.ContentType.Equal(oidSM2Data) {
return nil, nil, fmt.Errorf("cfca: unsupported content type oid <%v>", keys.EncryptedKey.ContentType)
}
if !keys.EncryptedKey.Algorithm.Equal(oidSM4) && !keys.EncryptedKey.Algorithm.Equal(oidSM4CBC) {
return nil, nil, fmt.Errorf("cfca: unsupported algorithm <%v>", keys.EncryptedKey.Algorithm)
}
pk, err := DecryptBySM4CBC(keys.EncryptedKey.EncryptedContent.Bytes, password)
if err != nil {
return nil, nil, fmt.Errorf("cfca: failed to decrypt by SM4-CBC, please ensure the password is correct: %v", err)
}
prvKey, err := sm2.NewPrivateKeyFromInt(new(big.Int).SetBytes(pk))
if err != nil {
return nil, nil, err
}
cert, err := smx509.ParseCertificate(keys.Certificate.Content)
if err != nil {
return nil, nil, err
}
if !prvKey.PublicKey.Equal(cert.PublicKey) {
return nil, nil, errors.New("cfca: public key and private key do not match")
}
return prvKey, cert, nil
}
// MarshalSM2 encodes sm2 private key and related certificate to cfca defined format.
// This method is corresponding to CFCA SADK's cfca.sadk.asn1.pkcs.CombineSM2Data.
func MarshalSM2(password []byte, key *sm2.PrivateKey, cert *smx509.Certificate) ([]byte, error) {
var err error
var ciphertext []byte
if ciphertext, err = EncryptBySM4CBC(key.D.Bytes(), password); err != nil {
return nil, err
}
if ciphertext, err = asn1.Marshal(ciphertext); err != nil {
return nil, err
}
keys := cfcaKeyPairData{
Version: 1,
EncryptedKey: keyData{
ContentType: oidSM2Data,
Algorithm: oidSM4,
EncryptedContent: asn1.RawValue{FullBytes: ciphertext},
},
Certificate: certData{
ContentType: oidSM2Data,
Content: cert.Raw,
},
}
return asn1.Marshal(keys)
}

205
cfca/pkcs12_sm2_test.go Normal file
View File

@ -0,0 +1,205 @@
package cfca
import (
"encoding/hex"
"encoding/pem"
"errors"
"math/big"
"testing"
"github.com/emmansun/gmsm/sm2"
"github.com/emmansun/gmsm/smx509"
)
var v2exKeyPem = `-----BEGIN CFCA KEY-----
MIIDSQIBATBHBgoqgRzPVQYBBAIBBgcqgRzPVQFoBDDkLvKllj9ZWhaKU6MSnxBBV5yaF3tEcOk1
vQniWyVzyaQA4F3j/YvDJwEoE8gOF/swggL5BgoqgRzPVQYBBAIBBIIC6TCCAuUwggKJoAMCAQIC
BRBAmQgJMAwGCCqBHM9VAYN1BQAwXDELMAkGA1UEBhMCQ04xMDAuBgNVBAoMJ0NoaW5hIEZpbmFu
Y2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEbMBkGA1UEAwwSQ0ZDQSBURVNUIFNNMiBPQ0Ex
MB4XDTIwMTExOTA4MzExOFoXDTI1MTExOTA4MzExOFowgYkxCzAJBgNVBAYTAkNOMRcwFQYDVQQK
DA5DRkNBIFRFU1QgT0NBMTENMAsGA1UECwwEUFNCQzEZMBcGA1UECwwQT3JnYW5pemF0aW9uYWwt
MjE3MDUGA1UEAwwuMDUxQOmCruWCqOe6v+S4iuaUtuWNleWVhuaIt0BONTEwMTEzMDAwMTg4NzhA
MTBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABJVRC63OKfcL4H324rDOdb4SSlbAjoJDXnK0qmwX
Z59FWmiSqt3ipreljKew4QynjTgR/yfp9yjNgNU8G5pkYdujggEGMIIBAjAfBgNVHSMEGDAWgBRr
/hjaj0I6prhtsy6Igzo0osEw4TAMBgNVHRMBAf8EAjAAMEgGA1UdIARBMD8wPQYIYIEchu8qAQEw
MTAvBggrBgEFBQcCARYjaHR0cDovL3d3dy5jZmNhLmNvbS5jbi91cy91cy0xNC5odG0wOQYDVR0f
BDIwMDAuoCygKoYoaHR0cDovL3VjcmwuY2ZjYS5jb20uY24vU00yL2NybDE0MzU2LmNybDAOBgNV
HQ8BAf8EBAMCBsAwHQYDVR0OBBYEFPiGPZT0oTuRXvkyGoOgviNEWnc1MB0GA1UdJQQWMBQGCCsG
AQUFBwMCBggrBgEFBQcDBDAMBggqgRzPVQGDdQUAA0gAMEUCIQCJDSsVPfhr+gnDASMj5Syt+hxs
amHygPecjCLbcdFQQgIgSXC4musF5Fnj/CpNTqvk9+56FuINkATGS8xRh7kzKBE=
-----END CFCA KEY-----
`
var cfcasm2oca1 = `-----BEGIN CERTIFICATE-----
MIICTTCCAfKgAwIBAgIKZCTXgL0MKPOtBzAMBggqgRzPVQGDdQUAMF0xCzAJBgNV
BAYTAkNOMTAwLgYDVQQKDCdDaGluYSBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkxHDAaBgNVBAMME0NGQ0EgVEVTVCBDUyBTTTIgQ0EwHhcNMTIxMjI1
MTIyNTA2WhcNMzIwNzIzMTIyNTA2WjBcMQswCQYDVQQGEwJDTjEwMC4GA1UECgwn
Q2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRswGQYDVQQD
DBJDRkNBIFRFU1QgU00yIE9DQTEwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAAQz
uFgJbedY55u6NToJElGWzPT+9UF1dxcopnerNO3fqRd4C1lDzz9LJZSfmMyNYaky
YC+6zh9G6/aPXW1Od/RFo4GYMIGVMB8GA1UdIwQYMBaAFLXYkG9c8Ngz0mO9frLD
jcZPEnphMAwGA1UdEwQFMAMBAf8wOAYDVR0fBDEwLzAtoCugKYYnaHR0cDovLzIx
MC43NC40Mi4zL3Rlc3RyY2EvU00yL2NybDEuY3JsMAsGA1UdDwQEAwIBBjAdBgNV
HQ4EFgQUa/4Y2o9COqa4bbMuiIM6NKLBMOEwDAYIKoEcz1UBg3UFAANHADBEAiAR
kDmkQ0Clio48994IUs63nA8k652O2C4+7EQs1SSbuAIgcwNUrHJyEYX8xT5BKl9T
lJOefzCNNJW5Z0f3Y/SjaG0=
-----END CERTIFICATE-----
`
func parseTestKeyAndCert() (*sm2.PrivateKey, *smx509.Certificate, error) {
password := []byte("123456")
var block *pem.Block
block, rest := pem.Decode([]byte(v2exKeyPem))
if len(rest) != 0 {
return nil, nil, errors.New("unexpected remaining PEM block during decode")
}
return ParseSM2(password, block.Bytes)
}
func TestParseSM2(t *testing.T) {
cases := []struct {
pem string
password []byte
}{
{
v2exKeyPem,
[]byte("123456"),
},
{
`-----BEGIN CFCA KEY-----
MIIDmwIBATBHBgoqgRzPVQYBBAIBBgcqgRzPVQFoBDAjEsMB1LZrH4B5zBJQLh/S3vLTegY5twIU
lKu80vkB3XLfImABwhYVzFkjfJY1lWEwggNLBgoqgRzPVQYBBAIBBIIDOzCCAzcwggLaoAMCAQIC
BUQmAVGGMAwGCCqBHM9VAYN1BQAwXDELMAkGA1UEBhMCQ04xMDAuBgNVBAoMJ0NoaW5hIEZpbmFu
Y2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEbMBkGA1UEAwwSQ0ZDQSBBQ1MgU00yIE9DQTMx
MB4XDTIxMDcyMTA5NTMxMloXDTIxMDkyMTA5NTMxMlowbDELMAkGA1UEBhMCQ04xEzARBgNVBAoM
CkNGQ0EgT0NBMzExDzANBgNVBAsMBnlzZXBheTEVMBMGA1UECwwMSW5kaXZpZHVhbC0xMSAwHgYD
VQQDDBcwNTFAdGVzdF9zbTJAdGVzdF9zbTJAMjBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABIex
X8bD+NRAEyP9mKl8/OKHHfogP82NobcifE9zyFlH0MPyMyXnjMT4FBQ1HPGRTExIUvnnS1GnuG0E
gtF58oCjggF1MIIBcTBsBggrBgEFBQcBAQRgMF4wKAYIKwYBBQUHMAGGHGh0dHA6Ly9vY3NwLmNm
Y2EuY29tLmNuL29jc3AwMgYIKwYBBQUHMAKGJmh0dHA6Ly9jcmwuY2ZjYS5jb20uY24vb2NhMzEv
b2NhMzEuY2VyMB8GA1UdIwQYMBaAFAjY0SbESH2c7KyY6fF/YrmAzqlFMAkGA1UdEwQCMAAwSAYD
VR0gBEEwPzA9BghggRyG7yoBBDAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNu
L3VzL3VzLTE0Lmh0bTA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLmNmY2EuY29tLmNuL29j
YTMxL1NNMi9jcmwxNDQwLmNybDAOBgNVHQ8BAf8EBAMCBsAwHQYDVR0OBBYEFJDoMEr89lXvtODi
obIvu3LOpoiFMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAMBggqgRzPVQGDdQUAA0kA
MEYCIQCV2YwNr90ad1E5mZqzmdkU0E1CWie9K0lsml012slavgIhAM/++u/l1x5cCIPZsCOYrIy2
0N8+aiLInpgEnkw3wQMt
-----END CFCA KEY-----
`,
[]byte("ys123456"),
},
}
for _, c := range cases {
block, _ := pem.Decode([]byte(c.pem))
if block == nil {
t.Fatal("failed to decode PEM block")
}
priv, cert, err := ParseSM2(c.password, block.Bytes)
if err != nil {
t.Fatal(err)
}
if priv == nil {
t.Fatal("failed to parse private key")
}
if cert == nil {
t.Fatal("failed to parse certificate")
}
if !priv.PublicKey.Equal(cert.PublicKey) {
t.Fatal("public key mismatch")
}
}
}
func TestMarshalSM2(t *testing.T) {
password := []byte("changeit")
priv, cert, err := parseTestKeyAndCert()
if err != nil {
t.Fatal(err)
}
rootca1, err := smx509.ParseCertificatePEM([]byte(cfcasm2oca1))
if err != nil {
t.Fatal(err)
}
err = rootca1.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature)
if err != nil {
t.Fatal(err)
}
result, err := MarshalSM2(password, priv, cert)
if err != nil {
t.Fatal(err)
}
priv1, cert1, err := ParseSM2(password, result)
if err != nil {
t.Fatal(err)
}
if !priv.Equal(priv1) {
t.Fatal("not same private key")
}
if !cert.Equal(cert1) {
t.Fatal("not same certficate")
}
}
func TestParseSM2WithInvalidOID(t *testing.T) {
password := []byte("changeit")
testcases := []string{
"308203490201013047060a2a811ccf55060104020906072a811ccf5501680430016ca58c339f32f5bbe2b0491d5087c9b5de0f5aef4b4d0726941a0c21d9795f51e802f2a1596cc909d1638067ca28cc308202f9060a2a811ccf550601040201048202e9308202e530820289a00302010202051040990809300c06082a811ccf550183750500305c310b300906035504061302434e3130302e060355040a0c274368696e612046696e616e6369616c2043657274696669636174696f6e20417574686f72697479311b301906035504030c1243464341205445535420534d32204f434131301e170d3230313131393038333131385a170d3235313131393038333131385a308189310b300906035504061302434e31173015060355040a0c0e434643412054455354204f434131310d300b060355040b0c045053424331193017060355040b0c104f7267616e697a6174696f6e616c2d323137303506035504030c2e30353140e982aee582a8e7babfe4b88ae694b6e58d95e59586e688b7404e353130313133303030313838373840313059301306072a8648ce3d020106082a811ccf5501822d0342000495510badce29f70be07df6e2b0ce75be124a56c08e82435e72b4aa6c17679f455a6892aadde2a6b7a58ca7b0e10ca78d3811ff27e9f728cd80d53c1b9a6461dba382010630820102301f0603551d230418301680146bfe18da8f423aa6b86db32e88833a34a2c130e1300c0603551d130101ff0402300030480603551d200441303f303d060860811c86ef2a01013031302f06082b060105050702011623687474703a2f2f7777772e636663612e636f6d2e636e2f75732f75732d31342e68746d30390603551d1f04323030302ea02ca02a8628687474703a2f2f7563726c2e636663612e636f6d2e636e2f534d322f63726c31343335362e63726c300e0603551d0f0101ff0404030206c0301d0603551d0e04160414f8863d94f4a13b915ef9321a83a0be23445a7735301d0603551d250416301406082b0601050507030206082b06010505070304300c06082a811ccf5501837505000348003045022100890d2b153df86bfa09c3012323e52cadfa1c6c6a61f280f79c8c22db71d1504202204970b89aeb05e459e3fc2a4d4eabe4f7ee7a16e20d9004c64bcc5187b9332811",
"308203490201013047060a2a811ccf55060104020106072a811ccf5501680430016ca58c339f32f5bbe2b0491d5087c9b5de0f5aef4b4d0726941a0c21d9795f51e802f2a1596cc909d1638067ca28cc308202f9060a2a811ccf550601040209048202e9308202e530820289a00302010202051040990809300c06082a811ccf550183750500305c310b300906035504061302434e3130302e060355040a0c274368696e612046696e616e6369616c2043657274696669636174696f6e20417574686f72697479311b301906035504030c1243464341205445535420534d32204f434131301e170d3230313131393038333131385a170d3235313131393038333131385a308189310b300906035504061302434e31173015060355040a0c0e434643412054455354204f434131310d300b060355040b0c045053424331193017060355040b0c104f7267616e697a6174696f6e616c2d323137303506035504030c2e30353140e982aee582a8e7babfe4b88ae694b6e58d95e59586e688b7404e353130313133303030313838373840313059301306072a8648ce3d020106082a811ccf5501822d0342000495510badce29f70be07df6e2b0ce75be124a56c08e82435e72b4aa6c17679f455a6892aadde2a6b7a58ca7b0e10ca78d3811ff27e9f728cd80d53c1b9a6461dba382010630820102301f0603551d230418301680146bfe18da8f423aa6b86db32e88833a34a2c130e1300c0603551d130101ff0402300030480603551d200441303f303d060860811c86ef2a01013031302f06082b060105050702011623687474703a2f2f7777772e636663612e636f6d2e636e2f75732f75732d31342e68746d30390603551d1f04323030302ea02ca02a8628687474703a2f2f7563726c2e636663612e636f6d2e636e2f534d322f63726c31343335362e63726c300e0603551d0f0101ff0404030206c0301d0603551d0e04160414f8863d94f4a13b915ef9321a83a0be23445a7735301d0603551d250416301406082b0601050507030206082b06010505070304300c06082a811ccf5501837505000348003045022100890d2b153df86bfa09c3012323e52cadfa1c6c6a61f280f79c8c22db71d1504202204970b89aeb05e459e3fc2a4d4eabe4f7ee7a16e20d9004c64bcc5187b9332811",
"3082034a0201013048060a2a811ccf55060104020106082a811ccf550168010430016ca58c339f32f5bbe2b0491d5087c9b5de0f5aef4b4d0726941a0c21d9795f51e802f2a1596cc909d1638067ca28cc308202f9060a2a811ccf550601040201048202e9308202e530820289a00302010202051040990809300c06082a811ccf550183750500305c310b300906035504061302434e3130302e060355040a0c274368696e612046696e616e6369616c2043657274696669636174696f6e20417574686f72697479311b301906035504030c1243464341205445535420534d32204f434131301e170d3230313131393038333131385a170d3235313131393038333131385a308189310b300906035504061302434e31173015060355040a0c0e434643412054455354204f434131310d300b060355040b0c045053424331193017060355040b0c104f7267616e697a6174696f6e616c2d323137303506035504030c2e30353140e982aee582a8e7babfe4b88ae694b6e58d95e59586e688b7404e353130313133303030313838373840313059301306072a8648ce3d020106082a811ccf5501822d0342000495510badce29f70be07df6e2b0ce75be124a56c08e82435e72b4aa6c17679f455a6892aadde2a6b7a58ca7b0e10ca78d3811ff27e9f728cd80d53c1b9a6461dba382010630820102301f0603551d230418301680146bfe18da8f423aa6b86db32e88833a34a2c130e1300c0603551d130101ff0402300030480603551d200441303f303d060860811c86ef2a01013031302f06082b060105050702011623687474703a2f2f7777772e636663612e636f6d2e636e2f75732f75732d31342e68746d30390603551d1f04323030302ea02ca02a8628687474703a2f2f7563726c2e636663612e636f6d2e636e2f534d322f63726c31343335362e63726c300e0603551d0f0101ff0404030206c0301d0603551d0e04160414f8863d94f4a13b915ef9321a83a0be23445a7735301d0603551d250416301406082b0601050507030206082b06010505070304300c06082a811ccf5501837505000348003045022100890d2b153df86bfa09c3012323e52cadfa1c6c6a61f280f79c8c22db71d1504202204970b89aeb05e459e3fc2a4d4eabe4f7ee7a16e20d9004c64bcc5187b9332811",
}
for _, testcase := range testcases {
der, _ := hex.DecodeString(testcase)
_, _, err := ParseSM2(password, der)
if err == nil {
t.Fatal("expected error")
}
}
}
func TestParseSM2WithInvalidPwd(t *testing.T) {
password := []byte("wrongpwd")
der, _ := hex.DecodeString("308203490201013047060a2a811ccf55060104020106072a811ccf5501680430016ca58c339f32f5bbe2b0491d5087c9b5de0f5aef4b4d0726941a0c21d9795f51e802f2a1596cc909d1638067ca28cc308202f9060a2a811ccf550601040201048202e9308202e530820289a00302010202051040990809300c06082a811ccf550183750500305c310b300906035504061302434e3130302e060355040a0c274368696e612046696e616e6369616c2043657274696669636174696f6e20417574686f72697479311b301906035504030c1243464341205445535420534d32204f434131301e170d3230313131393038333131385a170d3235313131393038333131385a308189310b300906035504061302434e31173015060355040a0c0e434643412054455354204f434131310d300b060355040b0c045053424331193017060355040b0c104f7267616e697a6174696f6e616c2d323137303506035504030c2e30353140e982aee582a8e7babfe4b88ae694b6e58d95e59586e688b7404e353130313133303030313838373840313059301306072a8648ce3d020106082a811ccf5501822d0342000495510badce29f70be07df6e2b0ce75be124a56c08e82435e72b4aa6c17679f455a6892aadde2a6b7a58ca7b0e10ca78d3811ff27e9f728cd80d53c1b9a6461dba382010630820102301f0603551d230418301680146bfe18da8f423aa6b86db32e88833a34a2c130e1300c0603551d130101ff0402300030480603551d200441303f303d060860811c86ef2a01013031302f06082b060105050702011623687474703a2f2f7777772e636663612e636f6d2e636e2f75732f75732d31342e68746d30390603551d1f04323030302ea02ca02a8628687474703a2f2f7563726c2e636663612e636f6d2e636e2f534d322f63726c31343335362e63726c300e0603551d0f0101ff0404030206c0301d0603551d0e04160414f8863d94f4a13b915ef9321a83a0be23445a7735301d0603551d250416301406082b0601050507030206082b06010505070304300c06082a811ccf5501837505000348003045022100890d2b153df86bfa09c3012323e52cadfa1c6c6a61f280f79c8c22db71d1504202204970b89aeb05e459e3fc2a4d4eabe4f7ee7a16e20d9004c64bcc5187b9332811")
_, _, err := ParseSM2(password, der)
if err == nil || err.Error() != "cfca: failed to decrypt by SM4-CBC, please ensure the password is correct: padding: invalid padding byte/length" {
t.Fatal("cfca: failed to decrypt by SM4-CBC, please ensure the password is correct: padding: invalid padding byte/length")
}
}
func TestMarshalSM2WithoutPwd(t *testing.T) {
priv, cert, err := parseTestKeyAndCert()
if err != nil {
t.Fatal(err)
}
_, err = MarshalSM2(nil, priv, cert)
if err == nil || err.Error() != "cfca: invalid password" {
t.Fatal(err)
}
}
func TestParseSM2Mismatch(t *testing.T) {
password := []byte("changeit")
privKey, _ := hex.DecodeString("6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85")
d := new(big.Int).SetBytes(privKey)
testkey := new(sm2.PrivateKey)
testkey.Curve = sm2.P256()
testkey.D = d
testkey.PublicKey.X, testkey.PublicKey.Y = testkey.ScalarBaseMult(testkey.D.Bytes())
_, cert, err := parseTestKeyAndCert()
if err != nil {
t.Fatal(err)
}
result, err := MarshalSM2(password, testkey, cert)
if err != nil {
t.Fatal(err)
}
_, _, err = ParseSM2(password, result)
if err == nil || err.Error() != "cfca: public key and private key do not match" {
t.Fatal("expected cfca: public key and private key do not match")
}
}

53
cfca/pkcs7_envelope.go Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cfca
import (
"crypto"
"github.com/emmansun/gmsm/pkcs"
"github.com/emmansun/gmsm/pkcs7"
"github.com/emmansun/gmsm/smx509"
)
// EnvelopeMessage creates and returns an envelope data PKCS7 structure (DER encoded) with encrypted
// recipient keys for each recipient public key.
//
// The OIDs use GM/T 0010 - 2012 set and the encrypted key uses ASN.1 format.
// This function uses recipient's SubjectKeyIdentifier to identify the recipient.
func EnvelopeMessage(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
return pkcs7.EnvelopeMessageCFCA(cipher, content, recipients)
}
// OpenEnvelopedMessage decrypts the enveloped message (DER encoded) using the provided certificate and private key.
// The certificate is used to identify the recipient and the private key is used to decrypt the encrypted key.
func OpenEnvelopedMessage(data []byte, recipientCert *smx509.Certificate, key crypto.PrivateKey) ([]byte, error) {
p7, err := pkcs7.Parse(data)
if err != nil {
return nil, err
}
return p7.Decrypt(recipientCert, key)
}
// EnvelopeMessageLegacy creates and returns an envelope data PKCS7 structure (DER encoded) with encrypted
// recipient keys for each recipient public key. This method is used for CFCA SADK verion less than 3.2 compatibility.
//
// The OIDs use GM/T 0010 - 2012 set and the encrypted key use C1C2C3 format and without 0x4 prefix.
// This function uses recipient's IssuerAndSerialNumber to identify the recipient.
func EnvelopeMessageLegacy(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
return pkcs7.EncryptCFCA(cipher, content, recipients)
}
// OpenEnvelopedMessageLegacy decrypts the enveloped message (DER encoded) using the provided certificate and private key.
// The certificate is used to identify the recipient and the private key is used to decrypt the encrypted key.
//
// This method is used for CFCA SADK verion less than 3.2 compatibility.
func OpenEnvelopedMessageLegacy(data []byte, recipientCert *smx509.Certificate, key crypto.PrivateKey) ([]byte, error) {
p7, err := pkcs7.Parse(data)
if err != nil {
return nil, err
}
return p7.DecryptCFCA(recipientCert, key)
}

171
cfca/pkcs7_envelope_test.go Normal file
View File

@ -0,0 +1,171 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cfca
import (
"bytes"
"crypto"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"fmt"
"math/big"
"testing"
"time"
"github.com/emmansun/gmsm/pkcs"
"github.com/emmansun/gmsm/sm2"
"github.com/emmansun/gmsm/smx509"
)
type certKeyPair struct {
Certificate *smx509.Certificate
PrivateKey crypto.PrivateKey
}
func createTestSM2Certificate(allCA bool) (certKeyPair, error) {
signer, err := createTestSM2CertificateByIssuer("Eddard Stark", nil, smx509.SM2WithSM3, true)
if err != nil {
return certKeyPair{}, err
}
pair, err := createTestSM2CertificateByIssuer("Jon Snow", signer, smx509.SM2WithSM3, allCA)
if err != nil {
return certKeyPair{}, err
}
return *pair, nil
}
func createTestSM2CertificateByIssuer(name string, issuer *certKeyPair, sigAlg x509.SignatureAlgorithm, isCA bool) (*certKeyPair, error) {
var (
err error
priv crypto.PrivateKey
derCert []byte
issuerCert *smx509.Certificate
issuerKey crypto.PrivateKey
)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 32)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, err
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: name,
Organization: []string{"Acme Co"},
},
NotBefore: time.Now().Add(-1 * time.Second),
NotAfter: time.Now().AddDate(1, 0, 0),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageEmailProtection},
}
if issuer != nil {
issuerCert = issuer.Certificate
issuerKey = issuer.PrivateKey
}
switch sigAlg {
case smx509.SM2WithSM3:
priv, err = sm2.GenerateKey(rand.Reader)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported signature algorithm %v", sigAlg)
}
if isCA {
template.IsCA = true
template.KeyUsage |= x509.KeyUsageCertSign
template.BasicConstraintsValid = true
}
if issuer == nil {
// no issuer given,make this a self-signed root cert
issuerCert = (*smx509.Certificate)(&template)
issuerKey = priv
}
switch pkey := priv.(type) {
case *sm2.PrivateKey:
derCert, err = smx509.CreateCertificate(rand.Reader, &template, (*x509.Certificate)(issuerCert), pkey.Public(), issuerKey)
default:
return nil, fmt.Errorf("unsupported private key type %T", pkey)
}
if err != nil {
return nil, err
}
if len(derCert) == 0 {
return nil, fmt.Errorf("no certificate created, probably due to wrong keys. types were %T and %T", priv, issuerKey)
}
cert, err := smx509.ParseCertificate(derCert)
if err != nil {
return nil, err
}
// pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
return &certKeyPair{
Certificate: cert,
PrivateKey: priv,
}, nil
}
func TestEnvelopeMessage(t *testing.T) {
ciphers := []pkcs.Cipher{
pkcs.SM4,
pkcs.SM4CBC,
}
for _, cipher := range ciphers {
plaintext := []byte("Hello Secret World!")
cert, err := createTestSM2Certificate(true)
if err != nil {
t.Fatal(err)
}
encrypted, err := EnvelopeMessage(cipher, plaintext, []*smx509.Certificate{cert.Certificate})
if err != nil {
t.Fatal(err)
}
_, err = OpenEnvelopedMessage(encrypted[:len(encrypted)-1], cert.Certificate, cert.PrivateKey)
if err == nil {
t.Fatalf("expected error when decrypting with wrong key, got nil")
}
// pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: encrypted})
result, err := OpenEnvelopedMessage(encrypted, cert.Certificate, cert.PrivateKey)
if err != nil {
t.Fatalf("cannot Decrypt encrypted result: %v", err)
}
if !bytes.Equal(plaintext, result) {
t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", plaintext, result)
}
}
}
func TestEnvelopeMessageLegacy(t *testing.T) {
ciphers := []pkcs.Cipher{
pkcs.SM4,
pkcs.SM4CBC,
}
for _, cipher := range ciphers {
plaintext := []byte("Hello Secret World!")
cert, err := createTestSM2Certificate(false)
if err != nil {
t.Fatal(err)
}
encrypted, err := EnvelopeMessageLegacy(cipher, plaintext, []*smx509.Certificate{cert.Certificate})
if err != nil {
t.Fatal(err)
}
_, err = OpenEnvelopedMessage(encrypted[:len(encrypted)-1], cert.Certificate, cert.PrivateKey)
if err == nil {
t.Fatalf("expected error when decrypting with wrong key, got nil")
}
// pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: encrypted})
result, err := OpenEnvelopedMessageLegacy(encrypted, cert.Certificate, cert.PrivateKey)
if err != nil {
t.Fatalf("cannot Decrypt encrypted result: %v", err)
}
if !bytes.Equal(plaintext, result) {
t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", plaintext, result)
}
}
}

83
cfca/pkcs7_sign.go Normal file
View File

@ -0,0 +1,83 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cfca
import (
"crypto"
"github.com/emmansun/gmsm/pkcs7"
"github.com/emmansun/gmsm/smx509"
)
func signMessage(data []byte, cert *smx509.Certificate, key crypto.PrivateKey, detached bool) ([]byte, error) {
signData, _ := pkcs7.NewSMSignedData(data)
if err := signData.SignWithoutAttr(cert, key, pkcs7.SignerInfoConfig{}); err != nil {
return nil, err
}
if detached {
signData.Detach()
}
return signData.Finish()
}
// SignMessageAttach signs the data with the certificate and private key, returns the signed data in PKCS7 (DER) format.
// This method corresponds to CFCA SADK's cfca.sadk.util.p7SignMessageAttach.
func SignMessageAttach(data []byte, cert *smx509.Certificate, key crypto.PrivateKey) ([]byte, error) {
return signMessage(data, cert, key, false)
}
// VerifyMessageAttach verifies the signed data in PKCS7 (DER) format.
// This method corresponds to CFCA SADK's cfca.sadk.util.p7VerifyMessageAttach.
// If verification fails, an error is returned. otherwise, nil is returned.
func VerifyMessageAttach(p7Der []byte) error {
p7, err := pkcs7.Parse(p7Der)
if err != nil {
return err
}
return p7.Verify()
}
// SignMessageDetach signs the data with the certificate and private key, returns the signed data in PKCS7 (DER) format.
// This method corresponds to CFCA SADK's cfca.sadk.util.p7SignMessageDetach.
func SignMessageDetach(data []byte, cert *smx509.Certificate, key crypto.PrivateKey) ([]byte, error) {
return signMessage(data, cert, key, true)
}
// VerifyMessageDetach verifies the signed data in PKCS7 (DER) format with the given source data.
// This method corresponds to CFCA SADK's cfca.sadk.util.p7VerifyMessageDetach.
// If verification fails, an error is returned. otherwise, nil is returned.
func VerifyMessageDetach(p7Der, sourceData []byte) error {
p7, err := pkcs7.Parse(p7Der)
if err != nil {
return err
}
p7.Content = sourceData
return p7.Verify()
}
// SignDigestDetach signs a given digest using the provided certificate and private key,
// and returns the detached PKCS7 signature.
//
// This method corresponds to CFCA SADK's cfca.sadk.util.p7SignByHash.
func SignDigestDetach(digest []byte, cert *smx509.Certificate, key crypto.PrivateKey) ([]byte, error) {
signData, _ := pkcs7.NewSMSignedDataWithDigest(digest)
if err := signData.SignWithoutAttr(cert, key, pkcs7.SignerInfoConfig{}); err != nil {
return nil, err
}
return signData.Finish()
}
// VerifyDigestDetach verifies a detached PKCS7 signature against a given digest.
// It parses the p7Der, assigns the provided digest to the parsed PKCS7 content, and then verifies it.
//
// This method corresponds to CFCA SADK's cfca.sadk.util.p7VerifyByHash.
func VerifyDigestDetach(p7Der, digest []byte) error {
p7, err := pkcs7.Parse(p7Der)
if err != nil {
return err
}
p7.Content = digest
return p7.VerifyAsDigest()
}

122
cfca/pkcs7_sign_test.go Normal file
View File

@ -0,0 +1,122 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cfca
import (
"crypto/ecdsa"
"encoding/base64"
"testing"
"github.com/emmansun/gmsm/sm2"
)
func TestSignMessageAttach(t *testing.T) {
_, err := SignMessageAttach(nil, nil, nil)
if err == nil {
t.Fatalf("SignMessageAttach() error = %v, wantErr %v", err, true)
}
pair, err := createTestSM2Certificate(false)
if err != nil {
t.Fatal(err)
}
_, err = SignMessageAttach([]byte("test"), pair.Certificate, nil)
if err == nil {
t.Fatalf("SignMessageAttach() error = %v, wantErr %v", err, true)
}
p7, err := SignMessageAttach([]byte("test"), pair.Certificate, pair.PrivateKey)
if err != nil {
t.Fatal(err)
}
p7[0] = 0x20
err = VerifyMessageAttach(p7)
if err == nil {
t.Fatalf("VerifyMessageAttach() error = %v, wantErr %v", err, true)
}
p7[0] = 0x30
err = VerifyMessageAttach(p7)
if err != nil {
t.Fatal(err)
}
p7, _ = base64.StdEncoding.DecodeString(sadkSignedData)
err = VerifyMessageAttach(p7)
if err != nil {
t.Fatal(err)
}
}
func TestSignMessageDetach(t *testing.T) {
_, err := SignMessageDetach(nil, nil, nil)
if err == nil {
t.Fatalf("SignMessageAttach() error = %v, wantErr %v", err, true)
}
pair, err := createTestSM2Certificate(false)
if err != nil {
t.Fatal(err)
}
_, err = SignMessageDetach([]byte("test"), pair.Certificate, nil)
if err == nil {
t.Fatalf("SignMessageAttach() error = %v, wantErr %v", err, true)
}
p7, err := SignMessageDetach([]byte("test"), pair.Certificate, pair.PrivateKey)
if err != nil {
t.Fatal(err)
}
p7[0] = 0x20
err = VerifyMessageDetach(p7, []byte("test"))
if err == nil {
t.Fatalf("VerifyMessageAttach() error = %v, wantErr %v", err, true)
}
p7[0] = 0x30
err = VerifyMessageDetach(p7, []byte("test"))
if err != nil {
t.Fatal(err)
}
err = VerifyMessageDetach(p7, []byte("test 1"))
if err == nil || err.Error() != "x509: SM2 verification failure" {
t.Fatalf("VerifyMessageAttach() error = %v, wantErr %v", err, true)
}
err = VerifyMessageDetach(p7, nil)
if err == nil || err.Error() != "x509: SM2 verification failure" {
t.Fatalf("VerifyMessageAttach() error = %v, wantErr %v", err, true)
}
p7, _ = base64.StdEncoding.DecodeString(sadkSignedDataDetach)
err = VerifyMessageDetach(p7, []byte("Hello Secret World!"))
if err != nil {
t.Fatal(err)
}
}
var sadkSignedData = "MIICgAYKKoEcz1UGAQQCAqCCAnAwggJsAgEBMQ4wDAYIKoEcz1UBgxEFADAjBgoqgRzPVQYBBAIBoBUEE0hlbGxvIFNlY3JldCBXb3JsZCGgggGNMIIBiTCCAS+gAwIBAgIFAKncGpAwCgYIKoEcz1UBg3UwKTEQMA4GA1UEChMHQWNtZSBDbzEVMBMGA1UEAxMMRWRkYXJkIFN0YXJrMB4XDTI0MTExOTAwMTIyNVoXDTI1MTExOTAwMTIyNlowJTEQMA4GA1UEChMHQWNtZSBDbzERMA8GA1UEAxMISm9uIFNub3cwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAATYcgrHXJmFO1/t/9WQ6GkCW6D0yDyd2ya5wRXjVAU08I9Oo6k99jB2MPauCn64W81APRCPHLlwWOtuIsmSmQhjo0gwRjAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwQwHwYDVR0jBBgwFoAUyBfYaeGJxaf9ST9aCRgotC+MwvwwCgYIKoEcz1UBg3UDSAAwRQIgRaF0PA74cCYKeu8pZ4VDQti+rE283Hq/tGXzXUzOWKUCIQDl3z1boZxtRscbnOGOXg1NY+yoY2lz5b63kGOTkn/SxzGBoDCBnQIBATAyMCkxEDAOBgNVBAoTB0FjbWUgQ28xFTATBgNVBAMTDEVkZGFyZCBTdGFyawIFAKncGpAwDAYIKoEcz1UBgxEFADANBgkqgRzPVQGCLQEFAARHMEUCIQCl145xtYc7QWTymATxUGbLfF1mlPlyMoIKSp9alu14UQIgQSV/Ll3yYCyXSNxhPelz8Nsbxopky+Pt56Al54rv3p0="
var sadkSignedDataDetach = "MIICaQYKKoEcz1UGAQQCAqCCAlkwggJVAgEBMQ4wDAYIKoEcz1UBgxEFADAMBgoqgRzPVQYBBAIBoIIBjTCCAYkwggEvoAMCAQICBQCp3BqQMAoGCCqBHM9VAYN1MCkxEDAOBgNVBAoTB0FjbWUgQ28xFTATBgNVBAMTDEVkZGFyZCBTdGFyazAeFw0yNDExMTkwMDEyMjVaFw0yNTExMTkwMDEyMjZaMCUxEDAOBgNVBAoTB0FjbWUgQ28xETAPBgNVBAMTCEpvbiBTbm93MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE2HIKx1yZhTtf7f/VkOhpAlug9Mg8ndsmucEV41QFNPCPTqOpPfYwdjD2rgp+uFvNQD0Qjxy5cFjrbiLJkpkIY6NIMEYwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMEMB8GA1UdIwQYMBaAFMgX2GnhicWn/Uk/WgkYKLQvjML8MAoGCCqBHM9VAYN1A0gAMEUCIEWhdDwO+HAmCnrvKWeFQ0LYvqxNvNx6v7Rl811MzlilAiEA5d89W6GcbUbHG5zhjl4NTWPsqGNpc+W+t5Bjk5J/0scxgaAwgZ0CAQEwMjApMRAwDgYDVQQKEwdBY21lIENvMRUwEwYDVQQDEwxFZGRhcmQgU3RhcmsCBQCp3BqQMAwGCCqBHM9VAYMRBQAwDQYJKoEcz1UBgi0BBQAERzBFAiEA4ylCl8qQDfNDfBw7VkxVN0bUs4N56TZDqZhAdEv01N8CIDtOG5VbmWNZeagC8VRfzEhu+ratFCo3fTu2liV8kH5h"
func TestSignDigestDetach(t *testing.T) {
_, err := SignDigestDetach(nil, nil, nil)
if err == nil {
t.Fatalf("SignDigestDetach() error = %v, wantErr %v", err, true)
}
pair, err := createTestSM2Certificate(false)
if err != nil {
t.Fatal(err)
}
rawMessage := []byte("test")
digest, err := sm2.CalculateSM2Hash(pair.Certificate.PublicKey.(*ecdsa.PublicKey), rawMessage, nil)
if err != nil {
t.Fatal(err)
}
p7, err := SignDigestDetach(digest, pair.Certificate, pair.PrivateKey)
if err != nil {
t.Fatal(err)
}
err = VerifyDigestDetach(p7, digest)
if err != nil {
t.Fatal(err)
}
err = VerifyMessageDetach(p7, rawMessage)
if err != nil {
t.Fatal(err)
}
}

132
cipher/bc.go Normal file
View File

@ -0,0 +1,132 @@
// Block Chaining operation mode (BC mode) in Chinese national standard GB/T 17964-2021.
// See GB/T 17964-2021 Chapter 12.
package cipher
import (
"bytes"
"crypto/cipher"
"crypto/subtle"
)
type bc struct {
b cipher.Block
blockSize int
iv []byte
}
func newBC(b cipher.Block, iv []byte) *bc {
return &bc{
b: b,
blockSize: b.BlockSize(),
iv: bytes.Clone(iv),
}
}
type bcEncrypter bc
// bcEncAble is an interface implemented by ciphers that have a specific
// optimized implementation of BC encryption.
// NewBCEncrypter will check for this interface and return the specific
// BlockMode if found.
type bcEncAble interface {
NewBCEncrypter(iv []byte) cipher.BlockMode
}
// NewBCEncrypter returns a BlockMode which encrypts in block chaining
// mode, using the given Block. The length of iv must be the same as the
// Block's block size.
func NewBCEncrypter(b cipher.Block, iv []byte) cipher.BlockMode {
if len(iv) != b.BlockSize() {
panic("cipher.NewBCEncrypter: IV length must equal block size")
}
if bc, ok := b.(bcEncAble); ok {
return bc.NewBCEncrypter(iv)
}
return (*bcEncrypter)(newBC(b, iv))
}
func (x *bcEncrypter) BlockSize() int { return x.blockSize }
func (x *bcEncrypter) CryptBlocks(dst, src []byte) {
validate(x.blockSize, dst, src)
iv := x.iv
for len(src) > 0 {
// Write the xor to dst, then encrypt in place.
subtle.XORBytes(dst[:x.blockSize], src[:x.blockSize], iv)
x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize])
subtle.XORBytes(iv, iv, dst[:x.blockSize])
src = src[x.blockSize:]
dst = dst[x.blockSize:]
}
// Save the iv for the next CryptBlocks call.
copy(x.iv, iv)
}
func (x *bcEncrypter) SetIV(iv []byte) {
if len(iv) != len(x.iv) {
panic("cipher: incorrect length IV")
}
copy(x.iv, iv)
}
type bcDecrypter bc
// bcDecAble is an interface implemented by ciphers that have a specific
// optimized implementation of BC decryption.
// NewBCDecrypter will check for this interface and return the specific
// BlockMode if found.
type bcDecAble interface {
NewBCDecrypter(iv []byte) cipher.BlockMode
}
// NewBCDecrypter returns a BlockMode which decrypts in block chaining
// mode, using the given Block. The length of iv must be the same as the
// Block's block size and must match the iv used to encrypt the data.
func NewBCDecrypter(b cipher.Block, iv []byte) cipher.BlockMode {
if len(iv) != b.BlockSize() {
panic("cipher.NewBCDecrypter: IV length must equal block size")
}
if bc, ok := b.(bcDecAble); ok {
return bc.NewBCDecrypter(iv)
}
return (*bcDecrypter)(newBC(b, iv))
}
func (x *bcDecrypter) BlockSize() int { return x.blockSize }
func (x *bcDecrypter) CryptBlocks(dst, src []byte) {
validate(x.blockSize, dst, src)
if len(src) == 0 {
return
}
iv := x.iv
nextIV := make([]byte, x.blockSize)
for len(src) > 0 {
// Get F(i+1)
subtle.XORBytes(nextIV, iv, src[:x.blockSize])
// Get plaintext P(i)
x.b.Decrypt(dst[:x.blockSize], src[:x.blockSize])
subtle.XORBytes(dst[:x.blockSize], dst[:x.blockSize], iv)
copy(iv, nextIV)
src = src[x.blockSize:]
dst = dst[x.blockSize:]
}
// Save the iv for the next CryptBlocks call.
copy(x.iv, iv)
}
func (x *bcDecrypter) SetIV(iv []byte) {
if len(iv) != len(x.iv) {
panic("cipher: incorrect length IV")
}
copy(x.iv, iv)
}

100
cipher/bc_test.go Normal file
View File

@ -0,0 +1,100 @@
package cipher_test
import (
"bytes"
"crypto/rand"
"encoding/hex"
"io"
mrand "math/rand"
"testing"
"time"
"github.com/emmansun/gmsm/cipher"
"github.com/emmansun/gmsm/internal/cryptotest"
"github.com/emmansun/gmsm/sm4"
)
var bcSM4TestVectors = []struct {
key string
iv string
plaintext string
ciphertext string
}{
{
"2B7E151628AED2A6ABF7158809CF4F3C",
"000102030405060708090A0B0C0D0E0F",
"6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710",
"AC529AF989A62FCE9CDDC5FFB84125CAFB8CDE77339FFE481D113C40BBD5B6786FFC9916F98F94FF12D78319707E240428718707605BC1EAC503153EBAA0FB1D",
},
}
func TestBC(t *testing.T) {
for i, test := range bcSM4TestVectors {
key, _ := hex.DecodeString(test.key)
iv, _ := hex.DecodeString(test.iv)
plaintext, _ := hex.DecodeString(test.plaintext)
ciphertext, _ := hex.DecodeString(test.ciphertext)
got := make([]byte, len(plaintext))
c, err := sm4.NewCipher(key)
if err != nil {
t.Fatal(err)
}
encrypter := cipher.NewBCEncrypter(c, iv)
encrypter.CryptBlocks(got, plaintext)
if !bytes.Equal(got, ciphertext) {
t.Fatalf("%v case encrypt failed, got %x\n", i+1, got)
}
decrypter := cipher.NewBCDecrypter(c, iv)
decrypter.CryptBlocks(got, ciphertext)
if !bytes.Equal(got, plaintext) {
t.Fatalf("%v case decrypt failed, got %x\n", i+1, got)
}
}
}
func TestSM4BCRandom(t *testing.T) {
key, _ := hex.DecodeString(bcSM4TestVectors[0].key)
iv := []byte("0123456789ABCDEF")
c, err := sm4.NewCipher(key)
if err != nil {
t.Fatal(err)
}
encrypter := cipher.NewBCEncrypter(c, iv)
decrypter := cipher.NewBCDecrypter(c, iv)
for i := 1; i <= 50; i++ {
plaintext := make([]byte, i*16)
ciphertext := make([]byte, i*16)
got := make([]byte, i*16)
io.ReadFull(rand.Reader, plaintext)
encrypter.CryptBlocks(ciphertext, plaintext)
decrypter.CryptBlocks(got, ciphertext)
if !bytes.Equal(got, plaintext) {
t.Errorf("test %v blocks failed", i)
}
}
}
// Test BC Blockmode against the general cipher.BlockMode interface tester
func TestBCBlockMode(t *testing.T) {
t.Run("SM4", func(t *testing.T) {
rng := newRandReader(t)
key := make([]byte, 16)
rng.Read(key)
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
cryptotest.TestBlockMode(t, block, cipher.NewBCEncrypter, cipher.NewBCDecrypter)
})
}
func newRandReader(t *testing.T) io.Reader {
seed := time.Now().UnixNano()
t.Logf("Deterministic RNG seed: 0x%x", seed)
return mrand.New(mrand.NewSource(seed))
}

View File

@ -1,17 +1,85 @@
package sm4_test
package cipher_test
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"testing"
smcipher "github.com/emmansun/gmsm/cipher"
"github.com/emmansun/gmsm/sm4"
)
func benchmarkCBCEncrypt1K(b *testing.B, block cipher.Block) {
func BenchmarkSM4BCEncrypt1K(b *testing.B) {
var key [16]byte
c, _ := sm4.NewCipher(key[:])
benchmarkBCEncrypt(b, c, make([]byte, 1024))
}
func benchmarkBCEncrypt(b *testing.B, block cipher.Block, buf []byte) {
b.SetBytes(int64(len(buf)))
var iv [16]byte
bc := smcipher.NewBCEncrypter(block, iv[:])
for i := 0; i < b.N; i++ {
bc.CryptBlocks(buf, buf)
}
}
func BenchmarkSM4BCDecrypt1K(b *testing.B) {
var key [16]byte
c, _ := sm4.NewCipher(key[:])
benchmarkBCDecrypt(b, c, make([]byte, 1024))
}
func benchmarkBCDecrypt(b *testing.B, block cipher.Block, buf []byte) {
b.SetBytes(int64(len(buf)))
var iv [16]byte
bc := smcipher.NewBCDecrypter(block, iv[:])
for i := 0; i < b.N; i++ {
bc.CryptBlocks(buf, buf)
}
}
func BenchmarkSM4HCTREncrypt1K(b *testing.B) {
var key [16]byte
var tweak [32]byte
c, _ := sm4.NewCipher(key[:])
io.ReadFull(rand.Reader, tweak[:])
hctr, _ := smcipher.NewHCTR(c, tweak[:16], tweak[16:])
buf := make([]byte, 1024)
b.SetBytes(int64(len(buf)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
hctr.EncryptBytes(buf, buf)
}
}
func benchmarkECBEncrypt(b *testing.B, block cipher.Block, buf []byte) {
b.SetBytes(int64(len(buf)))
ecb := smcipher.NewECBEncrypter(block)
for i := 0; i < b.N; i++ {
ecb.CryptBlocks(buf, buf)
}
}
func BenchmarkSM4ECBEncrypt1K(b *testing.B) {
var key [16]byte
c, _ := sm4.NewCipher(key[:])
benchmarkECBEncrypt(b, c, make([]byte, 1024))
}
func BenchmarkAES128ECBEncrypt1K(b *testing.B) {
var key [16]byte
c, _ := aes.NewCipher(key[:])
benchmarkECBEncrypt(b, c, make([]byte, 1024))
}
func benchmarkCBCEncrypt(b *testing.B, block cipher.Block, buf []byte) {
b.SetBytes(int64(len(buf)))
var iv [16]byte
cbc := cipher.NewCBCEncrypter(block, iv[:])
@ -23,17 +91,22 @@ func benchmarkCBCEncrypt1K(b *testing.B, block cipher.Block) {
func BenchmarkAESCBCEncrypt1K(b *testing.B) {
var key [16]byte
c, _ := aes.NewCipher(key[:])
benchmarkCBCEncrypt1K(b, c)
benchmarkCBCEncrypt(b, c, make([]byte, 1024))
}
func BenchmarkSM4CBCEncrypt1K(b *testing.B) {
var key [16]byte
c, _ := sm4.NewCipher(key[:])
benchmarkCBCEncrypt1K(b, c)
benchmarkCBCEncrypt(b, c, make([]byte, 1024))
}
func benchmarkSM4CBCDecrypt1K(b *testing.B, block cipher.Block) {
buf := make([]byte, 1024)
func BenchmarkSM4CBCEncrypt8K(b *testing.B) {
var key [16]byte
c, _ := sm4.NewCipher(key[:])
benchmarkCBCEncrypt(b, c, make([]byte, 8*1024))
}
func benchmarkCBCDecrypt(b *testing.B, block cipher.Block, buf []byte) {
b.SetBytes(int64(len(buf)))
var iv [16]byte
@ -46,21 +119,19 @@ func benchmarkSM4CBCDecrypt1K(b *testing.B, block cipher.Block) {
func BenchmarkAESCBCDecrypt1K(b *testing.B) {
var key [16]byte
c, _ := aes.NewCipher(key[:])
benchmarkSM4CBCDecrypt1K(b, c)
benchmarkCBCDecrypt(b, c, make([]byte, 1024))
}
func BenchmarkSM4CBCDecrypt1K(b *testing.B) {
var key [16]byte
c, _ := sm4.NewCipher(key[:])
benchmarkSM4CBCDecrypt1K(b, c)
benchmarkCBCDecrypt(b, c, make([]byte, 1024))
}
func benchmarkStream(b *testing.B, block cipher.Block, mode func(cipher.Block, []byte) cipher.Stream, buf []byte) {
b.SetBytes(int64(len(buf)))
//var key [16]byte
var iv [16]byte
//c, _ := sm4.NewCipher(key[:])
stream := mode(block, iv[:])
b.ResetTimer()
@ -362,54 +433,146 @@ func benchmarkSM4CCMOpen(b *testing.B, buf []byte) {
benchmarkGCMOpen(b, sm4gcm, buf)
}
func benchmarkXTS(b *testing.B, cipherFunc func([]byte) (cipher.Block, error), length, keylen int64) {
c, err := smcipher.NewXTS(cipherFunc, make([]byte, keylen))
if err != nil {
b.Fatalf("NewCipher failed: %s", err)
}
func benchmarkXTS(b *testing.B, isGB bool, cipherFunc func([]byte) (cipher.Block, error), length, keylen int64) {
plaintext := make([]byte, length)
encrypted := make([]byte, length)
//decrypted := make([]byte, length)
var c cipher.BlockMode
var err error
if !isGB {
c, err = smcipher.NewXTSEncrypterWithSector(cipherFunc, make([]byte, keylen), make([]byte, keylen), 0)
if err != nil {
b.Fatalf("NewCipher failed: %s", err)
}
} else {
c, err = smcipher.NewGBXTSEncrypterWithSector(cipherFunc, make([]byte, keylen), make([]byte, keylen), 0)
if err != nil {
b.Fatalf("NewCipher failed: %s", err)
}
}
b.SetBytes(int64(len(plaintext)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
c.Encrypt(encrypted, plaintext, 0)
//c.Decrypt(decrypted, encrypted[:len(plaintext)], 0)
c.CryptBlocks(encrypted, plaintext)
}
}
func BenchmarkAES128XTSEncrypt512(b *testing.B) {
benchmarkXTS(b, aes.NewCipher, 512, 32)
benchmarkXTS(b, false, aes.NewCipher, 512, 16)
}
func BenchmarkAES128XTSEncrypt1K(b *testing.B) {
benchmarkXTS(b, aes.NewCipher, 1024, 32)
benchmarkXTS(b, false, aes.NewCipher, 1024, 16)
}
func BenchmarkAES128XTSEncrypt4K(b *testing.B) {
benchmarkXTS(b, aes.NewCipher, 4096, 32)
benchmarkXTS(b, false, aes.NewCipher, 4096, 16)
}
func BenchmarkAES256XTSEncrypt512(b *testing.B) {
benchmarkXTS(b, aes.NewCipher, 512, 64)
benchmarkXTS(b, false, aes.NewCipher, 512, 32)
}
func BenchmarkAES256XTSEncrypt1K(b *testing.B) {
benchmarkXTS(b, aes.NewCipher, 1024, 64)
benchmarkXTS(b, false, aes.NewCipher, 1024, 32)
}
func BenchmarkAES256XTSEncrypt4K(b *testing.B) {
benchmarkXTS(b, aes.NewCipher, 4096, 64)
benchmarkXTS(b, false, aes.NewCipher, 4096, 32)
}
func BenchmarkSM4XTSEncrypt512(b *testing.B) {
benchmarkXTS(b, sm4.NewCipher, 512, 32)
benchmarkXTS(b, false, sm4.NewCipher, 512, 16)
}
func BenchmarkSM4XTSEncrypt1K(b *testing.B) {
benchmarkXTS(b, sm4.NewCipher, 1024, 32)
benchmarkXTS(b, false, sm4.NewCipher, 1024, 16)
}
func BenchmarkSM4XTSEncrypt4K(b *testing.B) {
benchmarkXTS(b, sm4.NewCipher, 4096, 32)
benchmarkXTS(b, false, sm4.NewCipher, 4096, 16)
}
func BenchmarkSM4XTSEncrypt512_GB(b *testing.B) {
benchmarkXTS(b, true, sm4.NewCipher, 512, 16)
}
func BenchmarkSM4XTSEncrypt1K_GB(b *testing.B) {
benchmarkXTS(b, true, sm4.NewCipher, 1024, 16)
}
func BenchmarkSM4XTSEncrypt4K_GB(b *testing.B) {
benchmarkXTS(b, true, sm4.NewCipher, 4096, 16)
}
func benchmarkXTS_Decrypt(b *testing.B, isGB bool, cipherFunc func([]byte) (cipher.Block, error), length, keylen int64) {
plaintext := make([]byte, length)
encrypted := make([]byte, length)
var c cipher.BlockMode
var err error
if !isGB {
c, err = smcipher.NewXTSDecrypterWithSector(cipherFunc, make([]byte, keylen), make([]byte, keylen), 0)
if err != nil {
b.Fatalf("NewCipher failed: %s", err)
}
} else {
c, err = smcipher.NewGBXTSDecrypterWithSector(cipherFunc, make([]byte, keylen), make([]byte, keylen), 0)
if err != nil {
b.Fatalf("NewCipher failed: %s", err)
}
}
b.SetBytes(int64(len(plaintext)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
c.CryptBlocks(plaintext, encrypted)
}
}
func BenchmarkAES128XTSDecrypt512(b *testing.B) {
benchmarkXTS_Decrypt(b, false, aes.NewCipher, 512, 16)
}
func BenchmarkAES128XTSDecrypt1K(b *testing.B) {
benchmarkXTS_Decrypt(b, false, aes.NewCipher, 1024, 16)
}
func BenchmarkAES128XTSDecrypt4K(b *testing.B) {
benchmarkXTS_Decrypt(b, false, aes.NewCipher, 4096, 16)
}
func BenchmarkAES256XTSDecrypt512(b *testing.B) {
benchmarkXTS_Decrypt(b, false, aes.NewCipher, 512, 32)
}
func BenchmarkAES256XTSDecrypt1K(b *testing.B) {
benchmarkXTS_Decrypt(b, false, aes.NewCipher, 1024, 32)
}
func BenchmarkAES256XTSDecrypt4K(b *testing.B) {
benchmarkXTS_Decrypt(b, false, aes.NewCipher, 4096, 32)
}
func BenchmarkSM4XTSDecrypt512(b *testing.B) {
benchmarkXTS_Decrypt(b, false, sm4.NewCipher, 512, 16)
}
func BenchmarkSM4XTSDecrypt1K(b *testing.B) {
benchmarkXTS_Decrypt(b, false, sm4.NewCipher, 1024, 16)
}
func BenchmarkSM4XTSDecrypt4K(b *testing.B) {
benchmarkXTS_Decrypt(b, false, sm4.NewCipher, 4096, 16)
}
func BenchmarkSM4XTSDecrypt512_GB(b *testing.B) {
benchmarkXTS_Decrypt(b, true, sm4.NewCipher, 512, 16)
}
func BenchmarkSM4XTSDecrypt1K_GB(b *testing.B) {
benchmarkXTS_Decrypt(b, true, sm4.NewCipher, 1024, 16)
}
func BenchmarkSM4XTSDecrypt4K_GB(b *testing.B) {
benchmarkXTS_Decrypt(b, true, sm4.NewCipher, 4096, 16)
}

357
cipher/cbc_sm4_test.go Normal file
View File

@ -0,0 +1,357 @@
package cipher_test
import (
"bytes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"testing"
"github.com/emmansun/gmsm/padding"
"github.com/emmansun/gmsm/sm4"
)
var cbcSM4Tests = []struct {
name string
key []byte
iv []byte
in []byte
out []byte
}{
{
"from internet",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World"),
[]byte{0x0a, 0x67, 0x06, 0x2f, 0x0c, 0xd2, 0xdc, 0xe2, 0x6a, 0x7b, 0x97, 0x8e, 0xbf, 0x21, 0x34, 0xf9},
},
{
"Three blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello Worldd"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0x06, 0x8d, 0x0f, 0xef, 0x4e, 0x2b, 0xfa, 0xb4, 0xbc, 0xab, 0xa6, 0x64, 0x41, 0xfd, 0xe0, 0xfe,
0x92, 0xc1, 0x64, 0xec, 0xa1, 0x70, 0x24, 0x75, 0x72, 0xde, 0x12, 0x02, 0x95, 0x2e, 0xc7, 0x27,
},
},
{
"Four blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hell"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0x34, 0x6e, 0x9d, 0xad, 0xe1, 0x8a, 0xf4, 0xa1, 0x83, 0x69, 0x57, 0xb9, 0x37, 0x26, 0x7e, 0x03,
},
},
{
"Five blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hello World Hello Wo"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0xb6, 0x09, 0x7b, 0xb8, 0x7e, 0xdb, 0x53, 0x4b, 0xea, 0x2a, 0xc6, 0xa1, 0xe5, 0xa0, 0x2a, 0xe9,
0x62, 0xb5, 0xe7, 0x50, 0x44, 0xea, 0x24, 0xcc, 0x9b, 0x5e, 0x07, 0x48, 0x04, 0x89, 0xa2, 0x74,
},
},
{
"7 blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hell"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0xb6, 0x09, 0x7b, 0xb8, 0x7e, 0xdb, 0x53, 0x4b, 0xea, 0x2a, 0xc6, 0xa1, 0xe5, 0xa0, 0x2a, 0xe9,
0x22, 0x65, 0x5b, 0xa3, 0xb9, 0xcc, 0x63, 0x92, 0x16, 0x0e, 0x2f, 0xf4, 0x3b, 0x93, 0x06, 0x82,
0xb3, 0x8c, 0x26, 0x2e, 0x06, 0x51, 0x34, 0x2c, 0xe4, 0x3d, 0xd0, 0xc7, 0x2b, 0x8f, 0x31, 0x15,
0xb7, 0x8f, 0xd0, 0x47, 0x45, 0x40, 0xec, 0x02, 0x1b, 0xef, 0xc1, 0xd2, 0xe5, 0xa2, 0x35, 0xd2,
},
},
{
"9 blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0xb6, 0x09, 0x7b, 0xb8, 0x7e, 0xdb, 0x53, 0x4b, 0xea, 0x2a, 0xc6, 0xa1, 0xe5, 0xa0, 0x2a, 0xe9,
0x22, 0x65, 0x5b, 0xa3, 0xb9, 0xcc, 0x63, 0x92, 0x16, 0x0e, 0x2f, 0xf4, 0x3b, 0x93, 0x06, 0x82,
0xb3, 0x8c, 0x26, 0x2e, 0x06, 0x51, 0x34, 0x2c, 0xe4, 0x3d, 0xd0, 0xc7, 0x2b, 0x8f, 0x31, 0x15,
0x30, 0xa8, 0x96, 0x1c, 0xbc, 0x8e, 0xf7, 0x4f, 0x6b, 0x69, 0x9d, 0xc9, 0x40, 0x89, 0xd7, 0xe8,
0xf7, 0x90, 0x47, 0x74, 0xaf, 0x40, 0xfd, 0x72, 0xc6, 0x17, 0xeb, 0xc0, 0x8b, 0x01, 0x71, 0x5c,
},
},
{
"10 blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0xb6, 0x09, 0x7b, 0xb8, 0x7e, 0xdb, 0x53, 0x4b, 0xea, 0x2a, 0xc6, 0xa1, 0xe5, 0xa0, 0x2a, 0xe9,
0x22, 0x65, 0x5b, 0xa3, 0xb9, 0xcc, 0x63, 0x92, 0x16, 0x0e, 0x2f, 0xf4, 0x3b, 0x93, 0x06, 0x82,
0xb3, 0x8c, 0x26, 0x2e, 0x06, 0x51, 0x34, 0x2c, 0xe4, 0x3d, 0xd0, 0xc7, 0x2b, 0x8f, 0x31, 0x15,
0x30, 0xa8, 0x96, 0x1c, 0xbc, 0x8e, 0xf7, 0x4f, 0x6b, 0x69, 0x9d, 0xc9, 0x40, 0x89, 0xd7, 0xe8,
0x2a, 0xe8, 0xc3, 0x3d, 0xcb, 0x8a, 0x1c, 0xb3, 0x70, 0x7d, 0xe9, 0xe6, 0x88, 0x36, 0x65, 0x21,
0x97, 0x0d, 0x27, 0xc6, 0x74, 0x49, 0x05, 0xa8, 0x28, 0x73, 0x65, 0x48, 0xb8, 0x81, 0x37, 0x6b,
},
},
{
"11 blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0xb6, 0x09, 0x7b, 0xb8, 0x7e, 0xdb, 0x53, 0x4b, 0xea, 0x2a, 0xc6, 0xa1, 0xe5, 0xa0, 0x2a, 0xe9,
0x22, 0x65, 0x5b, 0xa3, 0xb9, 0xcc, 0x63, 0x92, 0x16, 0x0e, 0x2f, 0xf4, 0x3b, 0x93, 0x06, 0x82,
0xb3, 0x8c, 0x26, 0x2e, 0x06, 0x51, 0x34, 0x2c, 0xe4, 0x3d, 0xd0, 0xc7, 0x2b, 0x8f, 0x31, 0x15,
0x30, 0xa8, 0x96, 0x1c, 0xbc, 0x8e, 0xf7, 0x4f, 0x6b, 0x69, 0x9d, 0xc9, 0x40, 0x89, 0xd7, 0xe8,
0x2a, 0xe8, 0xc3, 0x3d, 0xcb, 0x8a, 0x1c, 0xb3, 0x70, 0x7d, 0xe9, 0xe6, 0x88, 0x36, 0x65, 0x21,
0x7b, 0x34, 0xac, 0x73, 0x8d, 0x4f, 0x11, 0xde, 0xd4, 0x21, 0x45, 0x9f, 0x1f, 0x3e, 0xe8, 0xcf,
0x73, 0x8e, 0x70, 0xa7, 0x00, 0xc4, 0x27, 0x67, 0xa0, 0x9f, 0x91, 0xf4, 0xe3, 0x9e, 0x76, 0x15,
},
},
{
"12 blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0xb6, 0x09, 0x7b, 0xb8, 0x7e, 0xdb, 0x53, 0x4b, 0xea, 0x2a, 0xc6, 0xa1, 0xe5, 0xa0, 0x2a, 0xe9,
0x22, 0x65, 0x5b, 0xa3, 0xb9, 0xcc, 0x63, 0x92, 0x16, 0x0e, 0x2f, 0xf4, 0x3b, 0x93, 0x06, 0x82,
0xb3, 0x8c, 0x26, 0x2e, 0x06, 0x51, 0x34, 0x2c, 0xe4, 0x3d, 0xd0, 0xc7, 0x2b, 0x8f, 0x31, 0x15,
0x30, 0xa8, 0x96, 0x1c, 0xbc, 0x8e, 0xf7, 0x4f, 0x6b, 0x69, 0x9d, 0xc9, 0x40, 0x89, 0xd7, 0xe8,
0x2a, 0xe8, 0xc3, 0x3d, 0xcb, 0x8a, 0x1c, 0xb3, 0x70, 0x7d, 0xe9, 0xe6, 0x88, 0x36, 0x65, 0x21,
0x7b, 0x34, 0xac, 0x73, 0x8d, 0x4f, 0x11, 0xde, 0xd4, 0x21, 0x45, 0x9f, 0x1f, 0x3e, 0xe8, 0xcf,
0x50, 0x92, 0x8c, 0xa4, 0x79, 0x58, 0x3a, 0x26, 0x01, 0x7b, 0x99, 0x5c, 0xff, 0x8d, 0x66, 0x5b,
0x2e, 0x7d, 0x4e, 0xda, 0x3b, 0xe0, 0xef, 0x9d, 0x33, 0x2d, 0x2f, 0x6d, 0x47, 0x3f, 0x56, 0x8d,
},
},
{
"13 blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0xb6, 0x09, 0x7b, 0xb8, 0x7e, 0xdb, 0x53, 0x4b, 0xea, 0x2a, 0xc6, 0xa1, 0xe5, 0xa0, 0x2a, 0xe9,
0x22, 0x65, 0x5b, 0xa3, 0xb9, 0xcc, 0x63, 0x92, 0x16, 0x0e, 0x2f, 0xf4, 0x3b, 0x93, 0x06, 0x82,
0xb3, 0x8c, 0x26, 0x2e, 0x06, 0x51, 0x34, 0x2c, 0xe4, 0x3d, 0xd0, 0xc7, 0x2b, 0x8f, 0x31, 0x15,
0x30, 0xa8, 0x96, 0x1c, 0xbc, 0x8e, 0xf7, 0x4f, 0x6b, 0x69, 0x9d, 0xc9, 0x40, 0x89, 0xd7, 0xe8,
0x2a, 0xe8, 0xc3, 0x3d, 0xcb, 0x8a, 0x1c, 0xb3, 0x70, 0x7d, 0xe9, 0xe6, 0x88, 0x36, 0x65, 0x21,
0x7b, 0x34, 0xac, 0x73, 0x8d, 0x4f, 0x11, 0xde, 0xd4, 0x21, 0x45, 0x9f, 0x1f, 0x3e, 0xe8, 0xcf,
0x50, 0x92, 0x8c, 0xa4, 0x79, 0x58, 0x3a, 0x26, 0x01, 0x7b, 0x99, 0x5c, 0xff, 0x8d, 0x66, 0x5b,
0x07, 0x86, 0x0e, 0x22, 0xb4, 0xb4, 0x83, 0x74, 0x33, 0x79, 0xd0, 0x54, 0x9f, 0x03, 0x6b, 0x60,
0x4f, 0xae, 0xbd, 0x43, 0x34, 0x43, 0xb4, 0xee, 0x34, 0x22, 0xcc, 0xc5, 0xcd, 0xbd, 0x2d, 0x63,
},
},
{
"14 blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0xb6, 0x09, 0x7b, 0xb8, 0x7e, 0xdb, 0x53, 0x4b, 0xea, 0x2a, 0xc6, 0xa1, 0xe5, 0xa0, 0x2a, 0xe9,
0x22, 0x65, 0x5b, 0xa3, 0xb9, 0xcc, 0x63, 0x92, 0x16, 0x0e, 0x2f, 0xf4, 0x3b, 0x93, 0x06, 0x82,
0xb3, 0x8c, 0x26, 0x2e, 0x06, 0x51, 0x34, 0x2c, 0xe4, 0x3d, 0xd0, 0xc7, 0x2b, 0x8f, 0x31, 0x15,
0x30, 0xa8, 0x96, 0x1c, 0xbc, 0x8e, 0xf7, 0x4f, 0x6b, 0x69, 0x9d, 0xc9, 0x40, 0x89, 0xd7, 0xe8,
0x2a, 0xe8, 0xc3, 0x3d, 0xcb, 0x8a, 0x1c, 0xb3, 0x70, 0x7d, 0xe9, 0xe6, 0x88, 0x36, 0x65, 0x21,
0x7b, 0x34, 0xac, 0x73, 0x8d, 0x4f, 0x11, 0xde, 0xd4, 0x21, 0x45, 0x9f, 0x1f, 0x3e, 0xe8, 0xcf,
0x50, 0x92, 0x8c, 0xa4, 0x79, 0x58, 0x3a, 0x26, 0x01, 0x7b, 0x99, 0x5c, 0xff, 0x8d, 0x66, 0x5b,
0x07, 0x86, 0x0e, 0x22, 0xb4, 0xb4, 0x83, 0x74, 0x33, 0x79, 0xd0, 0x54, 0x9f, 0x03, 0x6b, 0x60,
0xa1, 0x52, 0x3c, 0x61, 0x1d, 0x91, 0xbf, 0x50, 0x00, 0xfb, 0x62, 0x58, 0xfa, 0xd3, 0xbd, 0x17,
0x28, 0x95, 0x7b, 0x51, 0x7e, 0x07, 0x6f, 0xfb, 0x8f, 0x9a, 0x4c, 0xbf, 0x33, 0xd5, 0xd7, 0xb6,
},
},
{
"15 blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0xb6, 0x09, 0x7b, 0xb8, 0x7e, 0xdb, 0x53, 0x4b, 0xea, 0x2a, 0xc6, 0xa1, 0xe5, 0xa0, 0x2a, 0xe9,
0x22, 0x65, 0x5b, 0xa3, 0xb9, 0xcc, 0x63, 0x92, 0x16, 0x0e, 0x2f, 0xf4, 0x3b, 0x93, 0x06, 0x82,
0xb3, 0x8c, 0x26, 0x2e, 0x06, 0x51, 0x34, 0x2c, 0xe4, 0x3d, 0xd0, 0xc7, 0x2b, 0x8f, 0x31, 0x15,
0x30, 0xa8, 0x96, 0x1c, 0xbc, 0x8e, 0xf7, 0x4f, 0x6b, 0x69, 0x9d, 0xc9, 0x40, 0x89, 0xd7, 0xe8,
0x2a, 0xe8, 0xc3, 0x3d, 0xcb, 0x8a, 0x1c, 0xb3, 0x70, 0x7d, 0xe9, 0xe6, 0x88, 0x36, 0x65, 0x21,
0x7b, 0x34, 0xac, 0x73, 0x8d, 0x4f, 0x11, 0xde, 0xd4, 0x21, 0x45, 0x9f, 0x1f, 0x3e, 0xe8, 0xcf,
0x50, 0x92, 0x8c, 0xa4, 0x79, 0x58, 0x3a, 0x26, 0x01, 0x7b, 0x99, 0x5c, 0xff, 0x8d, 0x66, 0x5b,
0x07, 0x86, 0x0e, 0x22, 0xb4, 0xb4, 0x83, 0x74, 0x33, 0x79, 0xd0, 0x54, 0x9f, 0x03, 0x6b, 0x60,
0xa1, 0x52, 0x3c, 0x61, 0x1d, 0x91, 0xbf, 0x50, 0x00, 0xfb, 0x62, 0x58, 0xfa, 0xd3, 0xbd, 0x17,
0x7d, 0x6f, 0xda, 0x76, 0x9a, 0xdb, 0x01, 0x96, 0x97, 0xc9, 0x5f, 0x64, 0x20, 0x3c, 0x70, 0x7a,
0xa3, 0xae, 0x6c, 0xce, 0x49, 0x31, 0x7a, 0xd3, 0x98, 0x01, 0xb0, 0x96, 0x2b, 0x4e, 0x81, 0x98,
},
},
{
"16 blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0xb6, 0x09, 0x7b, 0xb8, 0x7e, 0xdb, 0x53, 0x4b, 0xea, 0x2a, 0xc6, 0xa1, 0xe5, 0xa0, 0x2a, 0xe9,
0x22, 0x65, 0x5b, 0xa3, 0xb9, 0xcc, 0x63, 0x92, 0x16, 0x0e, 0x2f, 0xf4, 0x3b, 0x93, 0x06, 0x82,
0xb3, 0x8c, 0x26, 0x2e, 0x06, 0x51, 0x34, 0x2c, 0xe4, 0x3d, 0xd0, 0xc7, 0x2b, 0x8f, 0x31, 0x15,
0x30, 0xa8, 0x96, 0x1c, 0xbc, 0x8e, 0xf7, 0x4f, 0x6b, 0x69, 0x9d, 0xc9, 0x40, 0x89, 0xd7, 0xe8,
0x2a, 0xe8, 0xc3, 0x3d, 0xcb, 0x8a, 0x1c, 0xb3, 0x70, 0x7d, 0xe9, 0xe6, 0x88, 0x36, 0x65, 0x21,
0x7b, 0x34, 0xac, 0x73, 0x8d, 0x4f, 0x11, 0xde, 0xd4, 0x21, 0x45, 0x9f, 0x1f, 0x3e, 0xe8, 0xcf,
0x50, 0x92, 0x8c, 0xa4, 0x79, 0x58, 0x3a, 0x26, 0x01, 0x7b, 0x99, 0x5c, 0xff, 0x8d, 0x66, 0x5b,
0x07, 0x86, 0x0e, 0x22, 0xb4, 0xb4, 0x83, 0x74, 0x33, 0x79, 0xd0, 0x54, 0x9f, 0x03, 0x6b, 0x60,
0xa1, 0x52, 0x3c, 0x61, 0x1d, 0x91, 0xbf, 0x50, 0x00, 0xfb, 0x62, 0x58, 0xfa, 0xd3, 0xbd, 0x17,
0x7d, 0x6f, 0xda, 0x76, 0x9a, 0xdb, 0x01, 0x96, 0x97, 0xc9, 0x5f, 0x64, 0x20, 0x3c, 0x70, 0x7a,
0x40, 0x1f, 0x35, 0xc8, 0x22, 0xf2, 0x76, 0x6d, 0x8e, 0x4a, 0x78, 0xd7, 0x8d, 0x52, 0x51, 0x60,
0x71, 0xa7, 0x42, 0x07, 0xb2, 0x32, 0x3b, 0xa8, 0x5b, 0x15, 0x8f, 0x4e, 0x56, 0xef, 0xe0, 0x0a,
},
},
{
"17 blocks",
[]byte("0123456789ABCDEF"),
[]byte("0123456789ABCDEF"),
[]byte("Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World"),
[]byte{
0xd3, 0x1e, 0x36, 0x83, 0xe4, 0xfc, 0x9b, 0x51, 0x6a, 0x2c, 0x0f, 0x98, 0x36, 0x76, 0xa9, 0xeb,
0x1f, 0xdc, 0xc3, 0x2a, 0xf3, 0x84, 0x08, 0x97, 0x81, 0x57, 0xa2, 0x06, 0x5d, 0xe3, 0x4c, 0x6a,
0xe0, 0x02, 0xd6, 0xe4, 0xf5, 0x66, 0x87, 0xc4, 0xcc, 0x54, 0x1d, 0x1f, 0x1c, 0xc4, 0x2f, 0xe6,
0xe5, 0x1d, 0xea, 0x52, 0xb8, 0x0c, 0xc8, 0xbe, 0xae, 0xcc, 0x44, 0xa8, 0x51, 0x81, 0x08, 0x60,
0xb6, 0x09, 0x7b, 0xb8, 0x7e, 0xdb, 0x53, 0x4b, 0xea, 0x2a, 0xc6, 0xa1, 0xe5, 0xa0, 0x2a, 0xe9,
0x22, 0x65, 0x5b, 0xa3, 0xb9, 0xcc, 0x63, 0x92, 0x16, 0x0e, 0x2f, 0xf4, 0x3b, 0x93, 0x06, 0x82,
0xb3, 0x8c, 0x26, 0x2e, 0x06, 0x51, 0x34, 0x2c, 0xe4, 0x3d, 0xd0, 0xc7, 0x2b, 0x8f, 0x31, 0x15,
0x30, 0xa8, 0x96, 0x1c, 0xbc, 0x8e, 0xf7, 0x4f, 0x6b, 0x69, 0x9d, 0xc9, 0x40, 0x89, 0xd7, 0xe8,
0x2a, 0xe8, 0xc3, 0x3d, 0xcb, 0x8a, 0x1c, 0xb3, 0x70, 0x7d, 0xe9, 0xe6, 0x88, 0x36, 0x65, 0x21,
0x7b, 0x34, 0xac, 0x73, 0x8d, 0x4f, 0x11, 0xde, 0xd4, 0x21, 0x45, 0x9f, 0x1f, 0x3e, 0xe8, 0xcf,
0x50, 0x92, 0x8c, 0xa4, 0x79, 0x58, 0x3a, 0x26, 0x01, 0x7b, 0x99, 0x5c, 0xff, 0x8d, 0x66, 0x5b,
0x07, 0x86, 0x0e, 0x22, 0xb4, 0xb4, 0x83, 0x74, 0x33, 0x79, 0xd0, 0x54, 0x9f, 0x03, 0x6b, 0x60,
0xa1, 0x52, 0x3c, 0x61, 0x1d, 0x91, 0xbf, 0x50, 0x00, 0xfb, 0x62, 0x58, 0xfa, 0xd3, 0xbd, 0x17,
0x7d, 0x6f, 0xda, 0x76, 0x9a, 0xdb, 0x01, 0x96, 0x97, 0xc9, 0x5f, 0x64, 0x20, 0x3c, 0x70, 0x7a,
0x40, 0x1f, 0x35, 0xc8, 0x22, 0xf2, 0x76, 0x6d, 0x8e, 0x4a, 0x78, 0xd7, 0x8d, 0x52, 0x51, 0x60,
0x39, 0x14, 0xd8, 0xcd, 0xc7, 0x4b, 0x3f, 0xb3, 0x16, 0xdf, 0x52, 0xba, 0xcb, 0x98, 0x56, 0xaa,
0x97, 0x8b, 0xab, 0xa7, 0xbf, 0xe8, 0x0f, 0x16, 0x27, 0xbb, 0x56, 0xce, 0x10, 0xe5, 0x90, 0x05,
},
},
{
"A.1",
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{
0x68, 0x1e, 0xdf, 0x34, 0xd2, 0x06, 0x96, 0x5e, 0x86, 0xb3, 0xe9, 0x4f, 0x53, 0x6e, 0x42, 0x46,
0x67, 0x7d, 0x30, 0x7e, 0x84, 0x4d, 0x7a, 0xa2, 0x45, 0x79, 0xd5, 0x56, 0x49, 0x0d, 0xc7, 0xaa},
},
}
func TestCBCEncrypterSM4(t *testing.T) {
pkcs7 := padding.NewPKCS7Padding(sm4.BlockSize)
for _, test := range cbcSM4Tests {
c, err := sm4.NewCipher(test.key)
if err != nil {
t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
continue
}
encrypter := cipher.NewCBCEncrypter(c, test.iv)
plainText := pkcs7.Pad(test.in)
data := make([]byte, len(plainText))
copy(data, plainText)
encrypter.CryptBlocks(data, data)
if !bytes.Equal(test.out, data) {
t.Errorf("%s: CBCEncrypter\nhave %s\nwant %x", test.name, hex.EncodeToString(data), test.out)
for i := 0; i < len(data); i++ {
fmt.Printf("0x%02x, ", data[i])
if (i+1)%16 == 0 {
fmt.Println()
}
}
}
}
}
func TestCBCDecrypterSM4(t *testing.T) {
pkcs7 := padding.NewPKCS7Padding(sm4.BlockSize)
for _, test := range cbcSM4Tests {
c, err := sm4.NewCipher(test.key)
if err != nil {
t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
continue
}
decrypter := cipher.NewCBCDecrypter(c, test.iv)
data := make([]byte, len(test.out))
copy(data, test.out)
decrypter.CryptBlocks(data, data)
data, err = pkcs7.Unpad(data)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(test.in, data) {
t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test.name, data, test.in)
}
}
}
func TestSM4CBCRandom(t *testing.T) {
key := []byte("0123456789ABCDEF")
c, err := sm4.NewCipher(key)
if err != nil {
t.Fatal(err)
}
encrypter := cipher.NewCBCEncrypter(c, key)
decrypter := cipher.NewCBCDecrypter(c, key)
for i:=1; i<=50; i++ {
plaintext := make([]byte, i*16)
ciphertext := make([]byte, i*16)
got := make([]byte, i*16)
io.ReadFull(rand.Reader, plaintext)
encrypter.CryptBlocks(ciphertext, plaintext)
decrypter.CryptBlocks(got, ciphertext)
if !bytes.Equal(got, plaintext) {
t.Errorf("test %v blocks failed", i)
}
}
}

View File

@ -1,15 +1,15 @@
// Package cipher provides several extra chipher modes.
package cipher
import (
goCipher "crypto/cipher"
goSubtle "crypto/subtle"
"encoding/binary"
"crypto/cipher"
"crypto/subtle"
"math"
"errors"
"github.com/emmansun/gmsm/internal/subtle"
"github.com/emmansun/gmsm/internal/xor"
"github.com/emmansun/gmsm/internal/alias"
"github.com/emmansun/gmsm/internal/byteorder"
)
const (
@ -22,11 +22,11 @@ const (
// ccmAble is an interface implemented by ciphers that have a specific optimized
// implementation of CCM.
type ccmAble interface {
NewCCM(nonceSize, tagSize int) (goCipher.AEAD, error)
NewCCM(nonceSize, tagSize int) (cipher.AEAD, error)
}
type ccm struct {
cipher goCipher.Block
cipher cipher.Block
nonceSize int
tagSize int
}
@ -56,14 +56,14 @@ func maxlen(L, tagsize int) int {
// NewCCM returns the given 128-bit, block cipher wrapped in CCM
// with the standard nonce length.
func NewCCM(cipher goCipher.Block) (goCipher.AEAD, error) {
func NewCCM(cipher cipher.Block) (cipher.AEAD, error) {
return NewCCMWithNonceAndTagSize(cipher, ccmStandardNonceSize, ccmTagSize)
}
// NewCCMWithNonceSize returns the given 128-bit, block cipher wrapped in CCM,
// which accepts nonces of the given length. The length must not
// be zero.
func NewCCMWithNonceSize(cipher goCipher.Block, size int) (goCipher.AEAD, error) {
func NewCCMWithNonceSize(cipher cipher.Block, size int) (cipher.AEAD, error) {
return NewCCMWithNonceAndTagSize(cipher, size, ccmTagSize)
}
@ -71,13 +71,13 @@ func NewCCMWithNonceSize(cipher goCipher.Block, size int) (goCipher.AEAD, error)
// which generates tags with the given length.
//
// Tag sizes between 8 and 16 bytes are allowed.
//
func NewCCMWithTagSize(cipher goCipher.Block, tagSize int) (goCipher.AEAD, error) {
func NewCCMWithTagSize(cipher cipher.Block, tagSize int) (cipher.AEAD, error) {
return NewCCMWithNonceAndTagSize(cipher, ccmStandardNonceSize, tagSize)
}
// https://tools.ietf.org/html/rfc3610
func NewCCMWithNonceAndTagSize(cipher goCipher.Block, nonceSize, tagSize int) (goCipher.AEAD, error) {
// NewCCMWithNonceAndTagSize creates a new Counter with CBC-MAC (CCM) mode AEAD
// with the given nonce size and tag size.
func NewCCMWithNonceAndTagSize(cipher cipher.Block, nonceSize, tagSize int) (cipher.AEAD, error) {
if tagSize < ccmMinimumTagSize || tagSize > ccmBlockSize || tagSize&1 != 0 {
return nil, errors.New("cipher: incorrect tag size given to CCM")
}
@ -112,14 +112,14 @@ func (c *ccm) deriveCounter(counter *[ccmBlockSize]byte, nonce []byte) {
func (c *ccm) cmac(out, data []byte) {
for len(data) >= ccmBlockSize {
xor.XorBytes(out, out, data)
subtle.XORBytes(out, out, data)
c.cipher.Encrypt(out, out)
data = data[ccmBlockSize:]
}
if len(data) > 0 {
var block [ccmBlockSize]byte
copy(block[:], data)
xor.XorBytes(out, out, data)
subtle.XORBytes(out, out, data)
c.cipher.Encrypt(out, out)
}
}
@ -132,7 +132,7 @@ func (c *ccm) auth(nonce, plaintext, additionalData []byte, tagMask *[ccmBlockSi
}
out[0] |= byte(c.tagSize-2) << 2 // M' = ((tagSize - 2) / 2)*8
out[0] |= byte(14 - c.nonceSize) // L'
binary.BigEndian.PutUint64(out[ccmBlockSize-8:], uint64(len(plaintext)))
byteorder.BEPutUint64(out[ccmBlockSize-8:], uint64(len(plaintext)))
copy(out[1:], nonce)
// B0
c.cipher.Encrypt(out[:], out[:])
@ -142,7 +142,7 @@ func (c *ccm) auth(nonce, plaintext, additionalData []byte, tagMask *[ccmBlockSi
// First adata block includes adata length
i := 2
if n <= 0xfeff { // l(a) < (2^16 - 2^8)
binary.BigEndian.PutUint16(block[:i], uint16(n))
byteorder.BEPutUint16(block[:i], uint16(n))
} else {
block[0] = 0xff
// If (2^16 - 2^8) <= l(a) < 2^32, then the length field is encoded as
@ -151,14 +151,14 @@ func (c *ccm) auth(nonce, plaintext, additionalData []byte, tagMask *[ccmBlockSi
if n < uint64(1<<32) {
block[1] = 0xfe
i = 2 + 4
binary.BigEndian.PutUint32(block[2:i], uint32(n))
byteorder.BEPutUint32(block[2:i], uint32(n))
} else {
block[1] = 0xff
// If 2^32 <= l(a) < 2^64, then the length field is encoded as ten
// octets consisting of the octets 0xff, 0xff, and eight octets encoding
// l(a) in most-significant-byte-first order.
i = 2 + 8
binary.BigEndian.PutUint64(block[2:i], uint64(n))
byteorder.BEPutUint64(block[2:i], uint64(n))
}
}
i = copy(block[i:], additionalData) // first block start with additional data length
@ -168,7 +168,7 @@ func (c *ccm) auth(nonce, plaintext, additionalData []byte, tagMask *[ccmBlockSi
if len(plaintext) > 0 {
c.cmac(out[:], plaintext)
}
xor.XorWords(out[:], out[:], tagMask[:])
subtle.XORBytes(out[:], out[:], tagMask[:])
return out[:c.tagSize]
}
@ -179,8 +179,8 @@ func (c *ccm) Seal(dst, nonce, plaintext, data []byte) []byte {
if uint64(len(plaintext)) > uint64(c.MaxLength()) {
panic("cipher: message too large for CCM")
}
ret, out := subtle.SliceForAppend(dst, len(plaintext)+c.tagSize)
if subtle.InexactOverlap(out, plaintext) {
ret, out := alias.SliceForAppend(dst, len(plaintext)+c.tagSize)
if alias.InexactOverlap(out, plaintext) {
panic("cipher: invalid buffer overlap")
}
@ -189,7 +189,7 @@ func (c *ccm) Seal(dst, nonce, plaintext, data []byte) []byte {
c.cipher.Encrypt(tagMask[:], counter[:])
counter[len(counter)-1] |= 1
ctr := goCipher.NewCTR(c.cipher, counter[:])
ctr := cipher.NewCTR(c.cipher, counter[:])
ctr.XORKeyStream(out, plaintext)
tag := c.auth(nonce, plaintext, data, &tagMask)
@ -225,23 +225,21 @@ func (c *ccm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
c.deriveCounter(&counter, nonce)
c.cipher.Encrypt(tagMask[:], counter[:])
ret, out := subtle.SliceForAppend(dst, len(ciphertext))
if subtle.InexactOverlap(out, ciphertext) {
ret, out := alias.SliceForAppend(dst, len(ciphertext))
if alias.InexactOverlap(out, ciphertext) {
panic("cipher: invalid buffer overlap")
}
counter[len(counter)-1] |= 1
ctr := goCipher.NewCTR(c.cipher, counter[:])
ctr := cipher.NewCTR(c.cipher, counter[:])
ctr.XORKeyStream(out, ciphertext)
expectedTag := c.auth(nonce, out, data, &tagMask)
if goSubtle.ConstantTimeCompare(expectedTag, tag) != 1 {
if subtle.ConstantTimeCompare(expectedTag, tag) != 1 {
// The AESNI code decrypts and authenticates concurrently, and
// so overwrites dst in the event of a tag mismatch. That
// behavior is mimicked here in order to be consistent across
// platforms.
for i := range out {
out[i] = 0
}
clear(out)
return nil, errOpen
}
return ret, nil

31
cipher/ccm_64bit_test.go Normal file
View File

@ -0,0 +1,31 @@
//go:build !(arm || mips)
package cipher_test
import (
"crypto/aes"
"encoding/hex"
"testing"
"github.com/emmansun/gmsm/cipher"
)
func TestCCMLongAd(t *testing.T) {
key, _ := hex.DecodeString("ab72c77b97cb5fe9a382d9fe81ffdbed")
nonce, _ := hex.DecodeString("54cc7dc2c37ec006bcc6d1db")
c, _ := aes.NewCipher(key)
aesccm, _ := cipher.NewCCM(c)
ad := make([]byte, 0x10000)
ct := aesccm.Seal(nil, nonce, nil, ad)
if hex.EncodeToString(ct) != "e1ad65c3bfaba94b1085aff8c6ea2698" {
t.Errorf("got %s, want e1ad65c3bfaba94b1085aff8c6ea2698", hex.EncodeToString(ct))
}
ad = make([]byte, 1<<32+1)
ct = aesccm.Seal(nil, nonce, nil, ad)
if hex.EncodeToString(ct) != "c1949a661c605ff5640a29dd3e285ddb" {
t.Errorf("got %s, want c1949a661c605ff5640a29dd3e285ddb", hex.EncodeToString(ct))
}
}

View File

@ -1,4 +1,4 @@
package sm4_test
package cipher_test
import (
"encoding/hex"
@ -41,7 +41,6 @@ func TestCCM(t *testing.T) {
continue
}
//func (c *ccm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error)
pt, err := sm4ccm.Open(nil, nonce, ct, ad)
if err != nil {
t.Fatal(err)

View File

@ -1,9 +1,11 @@
package cipher
package cipher_test
import (
"crypto/aes"
"encoding/hex"
"testing"
"github.com/emmansun/gmsm/cipher"
)
// https://tools.ietf.org/html/rfc3610, 8. Test Vectors
@ -189,7 +191,7 @@ var aesCCMTests = []struct {
},
}
func TestCCM(t *testing.T) {
func TestCCMWithAES(t *testing.T) {
for i, tt := range aesCCMTests {
nonce, _ := hex.DecodeString(tt.nonce)
plaintext, _ := hex.DecodeString(tt.plaintext)
@ -199,7 +201,7 @@ func TestCCM(t *testing.T) {
if err != nil {
t.Fatal(err)
}
aesccm, err := NewCCMWithNonceAndTagSize(c, len(nonce), tt.tagSize)
aesccm, err := cipher.NewCCMWithNonceAndTagSize(c, len(nonce), tt.tagSize)
if err != nil {
t.Fatal(err)
}
@ -227,20 +229,33 @@ func TestCCMInvalidTagSize(t *testing.T) {
c, _ := aes.NewCipher(key)
for _, tagSize := range []int{0, 1, c.BlockSize() + 1} {
aesccm, err := NewCCMWithTagSize(c, tagSize)
aesccm, err := cipher.NewCCMWithTagSize(c, tagSize)
if aesccm != nil || err == nil {
t.Fatalf("NewCCMWithNonceAndTagSize was successful with an invalid %d-byte tag size", tagSize)
}
}
}
func TestTagFailureOverwrite(t *testing.T) {
func TestCCMInvalidNonceSize(t *testing.T) {
key, _ := hex.DecodeString("ab72c77b97cb5fe9a382d9fe81ffdbed")
c, _ := aes.NewCipher(key)
for _, nonceSize := range []int{0, 1, c.BlockSize() + 1} {
aesccm, err := cipher.NewCCMWithNonceSize(c, nonceSize)
if aesccm != nil || err == nil {
t.Fatalf("NewCCMWithNonceSize was successful with an invalid %d-byte tag size", nonceSize)
}
}
}
func TestCCMTagFailureOverwrite(t *testing.T) {
key, _ := hex.DecodeString("ab72c77b97cb5fe9a382d9fe81ffdbed")
nonce, _ := hex.DecodeString("54cc7dc2c37ec006bcc6d1db")
ciphertext, _ := hex.DecodeString("0e1bde206a07a9c2c1b65300f8c649972b4401346697138c7a4891ee59867d0c")
c, _ := aes.NewCipher(key)
aesccm, _ := NewCCM(c)
aesccm, _ := cipher.NewCCM(c)
dst := make([]byte, len(ciphertext)-16)
for i := range dst {

View File

@ -1,4 +1,4 @@
package sm4_test
package cipher_test
import (
"bytes"
@ -7,6 +7,7 @@ import (
"encoding/hex"
"testing"
"github.com/emmansun/gmsm/internal/cryptotest"
"github.com/emmansun/gmsm/sm4"
)
@ -105,3 +106,24 @@ func TestCFBInverse(t *testing.T) {
t.Errorf("got: %x, want: %x", plaintextCopy, plaintext)
}
}
func TestCFBStream(t *testing.T) {
t.Run("SM4", func(t *testing.T) {
rng := newRandReader(t)
key := make([]byte, 16)
rng.Read(key)
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
t.Run("Encrypter", func(t *testing.T) {
cryptotest.TestStreamFromBlock(t, block, cipher.NewCFBEncrypter)
})
t.Run("Decrypter", func(t *testing.T) {
cryptotest.TestStreamFromBlock(t, block, cipher.NewCFBDecrypter)
})
})
}

14
cipher/common.go Normal file
View File

@ -0,0 +1,14 @@
package cipher
import "crypto/cipher"
// blockSize is the block size that the underlying cipher must have.
const blockSize = 16
type concurrentBlocks interface {
Concurrency() int
EncryptBlocks(dst, src []byte)
DecryptBlocks(dst, src []byte)
}
type CipherCreator func([]byte) (cipher.Block, error)

186
cipher/ctr_sm4_test.go Normal file
View File

@ -0,0 +1,186 @@
package cipher_test
import (
"bytes"
"crypto/cipher"
"testing"
"github.com/emmansun/gmsm/internal/cryptotest"
"github.com/emmansun/gmsm/sm4"
)
var ctrSM4Tests = []struct {
name string
key []byte
iv []byte
in []byte
out []byte
}{
{
"2 blocks",
[]byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51},
[]byte{
0xbc, 0x71, 0x0d, 0x76, 0x2d, 0x07, 0x0b, 0x26, 0x36, 0x1d, 0xa8, 0x2b, 0x54, 0x56, 0x5e, 0x46,
0xb0, 0x2b, 0x3d, 0xbd, 0xdd, 0x50, 0xd5, 0xb4, 0x58, 0xae, 0xcc, 0xb2, 0x5d, 0xa1, 0x05, 0xe1},
},
{
"4 blocks",
[]byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
},
[]byte{
0xbc, 0x71, 0x0d, 0x76, 0x2d, 0x07, 0x0b, 0x26, 0x36, 0x1d, 0xa8, 0x2b, 0x54, 0x56, 0x5e, 0x46,
0xb0, 0x2b, 0x3d, 0xbd, 0xdd, 0x50, 0xd5, 0xb4, 0x58, 0xae, 0xcc, 0xb2, 0x5d, 0xa1, 0x05, 0xe1,
0x6a, 0xd7, 0x0b, 0xc0, 0x11, 0x75, 0xad, 0x43, 0xb0, 0x80, 0x6a, 0x2e, 0x7b, 0x9c, 0xa5, 0x45,
0x60, 0x24, 0x59, 0xa0, 0x6b, 0x7d, 0x13, 0x0d, 0xde, 0x42, 0xa3, 0xe0, 0x47, 0x68, 0x18, 0xd2,
},
},
{
"6 blocks",
[]byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
},
[]byte{
0xbc, 0x71, 0x0d, 0x76, 0x2d, 0x07, 0x0b, 0x26, 0x36, 0x1d, 0xa8, 0x2b, 0x54, 0x56, 0x5e, 0x46,
0xb0, 0x2b, 0x3d, 0xbd, 0xdd, 0x50, 0xd5, 0xb4, 0x58, 0xae, 0xcc, 0xb2, 0x5d, 0xa1, 0x05, 0xe1,
0x6a, 0xd7, 0x0b, 0xc0, 0x11, 0x75, 0xad, 0x43, 0xb0, 0x80, 0x6a, 0x2e, 0x7b, 0x9c, 0xa5, 0x45,
0x60, 0x24, 0x59, 0xa0, 0x6b, 0x7d, 0x13, 0x0d, 0xde, 0x42, 0xa3, 0xe0, 0x47, 0x68, 0x18, 0xd2,
0x00, 0xb8, 0x33, 0x1a, 0x66, 0x57, 0xd6, 0xbe, 0xb8, 0x5b, 0x72, 0x4f, 0x55, 0x0c, 0xd5, 0x2d,
0x96, 0xf3, 0xe4, 0x12, 0x37, 0xa2, 0x07, 0x44, 0x43, 0xa5, 0x43, 0x3a, 0x41, 0x33, 0x0d, 0xca,
},
},
{
"8 blocks",
[]byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
},
[]byte{
0xbc, 0x71, 0x0d, 0x76, 0x2d, 0x07, 0x0b, 0x26, 0x36, 0x1d, 0xa8, 0x2b, 0x54, 0x56, 0x5e, 0x46,
0xb0, 0x2b, 0x3d, 0xbd, 0xdd, 0x50, 0xd5, 0xb4, 0x58, 0xae, 0xcc, 0xb2, 0x5d, 0xa1, 0x05, 0xe1,
0x6a, 0xd7, 0x0b, 0xc0, 0x11, 0x75, 0xad, 0x43, 0xb0, 0x80, 0x6a, 0x2e, 0x7b, 0x9c, 0xa5, 0x45,
0x60, 0x24, 0x59, 0xa0, 0x6b, 0x7d, 0x13, 0x0d, 0xde, 0x42, 0xa3, 0xe0, 0x47, 0x68, 0x18, 0xd2,
0x00, 0xb8, 0x33, 0x1a, 0x66, 0x57, 0xd6, 0xbe, 0xb8, 0x5b, 0x72, 0x4f, 0x55, 0x0c, 0xd5, 0x2d,
0x96, 0xf3, 0xe4, 0x12, 0x37, 0xa2, 0x07, 0x44, 0x43, 0xa5, 0x43, 0x3a, 0x41, 0x33, 0x0d, 0xca,
0x41, 0xb7, 0x3a, 0x57, 0x17, 0x65, 0xef, 0x3d, 0xbb, 0xd1, 0x04, 0x5d, 0xb7, 0xf8, 0x71, 0x39,
0xff, 0x82, 0x01, 0x19, 0x75, 0xaf, 0x8a, 0x01, 0x8a, 0x0a, 0x26, 0x93, 0x85, 0xfd, 0x04, 0x5f,
},
},
{
"16 blocks",
[]byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
},
[]byte{
0xbc, 0x71, 0x0d, 0x76, 0x2d, 0x07, 0x0b, 0x26, 0x36, 0x1d, 0xa8, 0x2b, 0x54, 0x56, 0x5e, 0x46,
0xb0, 0x2b, 0x3d, 0xbd, 0xdd, 0x50, 0xd5, 0xb4, 0x58, 0xae, 0xcc, 0xb2, 0x5d, 0xa1, 0x05, 0xe1,
0x6a, 0xd7, 0x0b, 0xc0, 0x11, 0x75, 0xad, 0x43, 0xb0, 0x80, 0x6a, 0x2e, 0x7b, 0x9c, 0xa5, 0x45,
0x60, 0x24, 0x59, 0xa0, 0x6b, 0x7d, 0x13, 0x0d, 0xde, 0x42, 0xa3, 0xe0, 0x47, 0x68, 0x18, 0xd2,
0x00, 0xb8, 0x33, 0x1a, 0x66, 0x57, 0xd6, 0xbe, 0xb8, 0x5b, 0x72, 0x4f, 0x55, 0x0c, 0xd5, 0x2d,
0x96, 0xf3, 0xe4, 0x12, 0x37, 0xa2, 0x07, 0x44, 0x43, 0xa5, 0x43, 0x3a, 0x41, 0x33, 0x0d, 0xca,
0x41, 0xb7, 0x3a, 0x57, 0x17, 0x65, 0xef, 0x3d, 0xbb, 0xd1, 0x04, 0x5d, 0xb7, 0xf8, 0x71, 0x39,
0xff, 0x82, 0x01, 0x19, 0x75, 0xaf, 0x8a, 0x01, 0x8a, 0x0a, 0x26, 0x93, 0x85, 0xfd, 0x04, 0x5f,
0x73, 0xd4, 0xc6, 0x3a, 0x81, 0x0a, 0x91, 0xe3, 0xb9, 0x17, 0x89, 0xdf, 0x4c, 0xcd, 0xe8, 0xe3,
0x4e, 0xe7, 0x8d, 0x52, 0x89, 0x93, 0xb9, 0xef, 0x42, 0xe7, 0x5d, 0x67, 0xa8, 0x25, 0xad, 0xf0,
0xe2, 0x45, 0x9d, 0x8c, 0x30, 0x61, 0x8a, 0x26, 0x90, 0x4f, 0x52, 0x61, 0xa0, 0x61, 0x62, 0xfb,
0x36, 0xc8, 0x95, 0xe2, 0x8d, 0x75, 0x86, 0xf5, 0xbf, 0x22, 0x1c, 0xdd, 0xc9, 0x52, 0x71, 0x5a,
0x7e, 0xb0, 0x56, 0xd6, 0x8a, 0x7e, 0xfa, 0x4f, 0xda, 0x6b, 0x97, 0x95, 0x23, 0xa7, 0xa8, 0x39,
0x76, 0x31, 0x10, 0x79, 0x47, 0x98, 0x5b, 0x71, 0xbf, 0xc9, 0x4c, 0xce, 0xb7, 0xd4, 0x19, 0x86,
0x04, 0x87, 0xc0, 0xba, 0xe8, 0xa5, 0x4c, 0xc8, 0x48, 0x9c, 0x28, 0xd3, 0x4b, 0x4d, 0xfc, 0x3f,
0x9b, 0xbc, 0xf3, 0xd1, 0x9d, 0x25, 0x43, 0x47, 0x37, 0xea, 0xb7, 0x5e, 0x0d, 0xdb, 0x58, 0xf1,
},
},
}
func TestCTR_SM4(t *testing.T) {
for _, tt := range ctrSM4Tests {
test := tt.name
c, err := sm4.NewCipher(tt.key)
if err != nil {
t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
continue
}
for j := 0; j <= 5; j += 5 {
in := tt.in[0 : len(tt.in)-j]
ctr := cipher.NewCTR(c, tt.iv)
encrypted := make([]byte, len(in))
ctr.XORKeyStream(encrypted, in)
if out := tt.out[0:len(in)]; !bytes.Equal(out, encrypted) {
t.Errorf("%s/%d: CTR\ninpt %x\nhave %x\nwant %x", test, len(in), in, encrypted, out)
}
}
for j := 0; j <= 7; j += 7 {
in := tt.out[0 : len(tt.out)-j]
ctr := cipher.NewCTR(c, tt.iv)
plain := make([]byte, len(in))
ctr.XORKeyStream(plain, in)
if out := tt.in[0:len(in)]; !bytes.Equal(out, plain) {
t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), plain, out)
}
}
if t.Failed() {
break
}
}
}
func TestCTRStream(t *testing.T) {
t.Run("SM4", func(t *testing.T) {
rng := newRandReader(t)
key := make([]byte, 16)
rng.Read(key)
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
cryptotest.TestStreamFromBlock(t, block, cipher.NewCTR)
})
}

100
cipher/ecb.go Normal file
View File

@ -0,0 +1,100 @@
// Electronic Code Book (ECB) mode.
// Please do NOT use this mode alone.
package cipher
import (
goCipher "crypto/cipher"
"github.com/emmansun/gmsm/internal/alias"
)
type ecb struct {
b goCipher.Block
blockSize int
}
func newECB(b goCipher.Block) *ecb {
return &ecb{
b: b,
blockSize: b.BlockSize(),
}
}
func validate(size int, dst, src []byte) {
if len(src)%size != 0 {
panic("cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("cipher: output smaller than input")
}
if alias.InexactOverlap(dst[:len(src)], src) {
panic("cipher: invalid buffer overlap")
}
}
type ecbEncrypter ecb
// ecbEncAble is an interface implemented by ciphers that have a specific
// optimized implementation of ECB encryption, like sm4.
// NewECBEncrypter will check for this interface and return the specific
// BlockMode if found.
type ecbEncAble interface {
NewECBEncrypter() goCipher.BlockMode
}
// NewECBEncrypter returns a BlockMode which encrypts in electronic code book
// mode, using the given Block.
func NewECBEncrypter(b goCipher.Block) goCipher.BlockMode {
if ecb, ok := b.(ecbEncAble); ok {
return ecb.NewECBEncrypter()
}
return (*ecbEncrypter)(newECB(b))
}
func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
validate(x.blockSize, dst, src)
for len(src) > 0 {
x.b.Encrypt(dst[:x.blockSize], src[:x.blockSize])
src = src[x.blockSize:]
dst = dst[x.blockSize:]
}
}
type ecbDecrypter ecb
// ecbDecAble is an interface implemented by ciphers that have a specific
// optimized implementation of ECB decryption, like sm4.
// NewECBDecrypter will check for this interface and return the specific
// BlockMode if found.
type ecbDecAble interface {
NewECBDecrypter() goCipher.BlockMode
}
// NewECBDecrypter returns a BlockMode which decrypts in electronic code book
// mode, using the given Block.
func NewECBDecrypter(b goCipher.Block) goCipher.BlockMode {
if ecb, ok := b.(ecbDecAble); ok {
return ecb.NewECBDecrypter()
}
return (*ecbDecrypter)(newECB(b))
}
func (x *ecbDecrypter) BlockSize() int { return x.blockSize }
func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
validate(x.blockSize, dst, src)
if len(src) == 0 {
return
}
for len(src) > 0 {
x.b.Decrypt(dst[:x.blockSize], src[:x.blockSize])
src = src[x.blockSize:]
dst = dst[x.blockSize:]
}
}

145
cipher/ecb_sm4_test.go Normal file
View File

@ -0,0 +1,145 @@
package cipher_test
import (
"bytes"
"crypto/rand"
"io"
"testing"
"github.com/emmansun/gmsm/cipher"
"github.com/emmansun/gmsm/sm4"
)
var ecbSM4Tests = []struct {
name string
key []byte
in []byte
}{
{
"1 block",
[]byte("0123456789ABCDEF"),
[]byte("exampleplaintext"),
},
{
"2 same blocks",
[]byte("0123456789ABCDEF"),
[]byte("exampleplaintextexampleplaintext"),
},
{
"2 different blocks",
[]byte("0123456789ABCDEF"),
[]byte("exampleplaintextfedcba9876543210"),
},
{
"3 same blocks",
[]byte("0123456789ABCDEF"),
[]byte("exampleplaintextexampleplaintextexampleplaintext"),
},
{
"4 same blocks",
[]byte("0123456789ABCDEF"),
[]byte("exampleplaintextexampleplaintextexampleplaintextexampleplaintext"),
},
{
"5 same blocks",
[]byte("0123456789ABCDEF"),
[]byte("exampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintext"),
},
{
"6 same blocks",
[]byte("0123456789ABCDEF"),
[]byte("exampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintext"),
},
{
"7 same blocks",
[]byte("0123456789ABCDEF"),
[]byte("exampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintext"),
},
{
"8 same blocks",
[]byte("0123456789ABCDEF"),
[]byte("exampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintext"),
},
{
"9 same blocks",
[]byte("0123456789ABCDEF"),
[]byte("exampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintext"),
},
{
"18 same blocks",
[]byte("0123456789ABCDEF"),
[]byte("exampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintextexampleplaintext"),
},
}
func TestECBBasic(t *testing.T) {
for _, test := range ecbSM4Tests {
c, err := sm4.NewCipher(test.key)
if err != nil {
t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
continue
}
encrypter := cipher.NewECBEncrypter(c)
ciphertext := make([]byte, len(test.in))
encrypter.CryptBlocks(ciphertext, test.in)
plaintext := make([]byte, len(test.in))
decrypter := cipher.NewECBDecrypter(c)
decrypter.CryptBlocks(plaintext, ciphertext)
if !bytes.Equal(test.in, plaintext) {
t.Errorf("%s: ECB encrypt/decrypt failed, %s", test.name, string(plaintext))
}
}
}
func TestECBRandom(t *testing.T) {
key := []byte("0123456789ABCDEF")
plaintext := make([]byte, 464)
ciphertext := make([]byte, 464)
io.ReadFull(rand.Reader, plaintext)
c, err := sm4.NewCipher(key)
if err != nil {
t.Fatal(err)
}
encrypter := cipher.NewECBEncrypter(c)
encrypter.CryptBlocks(ciphertext, plaintext)
result := make([]byte, 464)
decrypter := cipher.NewECBDecrypter(c)
decrypter.CryptBlocks(result, ciphertext)
if !bytes.Equal(result, plaintext) {
t.Error("ECB encrypt/decrypt failed")
}
}
func shouldPanic(t *testing.T, f func()) {
t.Helper()
defer func() { _ = recover() }()
f()
t.Errorf("should have panicked")
}
func TestECBValidate(t *testing.T) {
key := make([]byte, 16)
src := make([]byte, 32)
c, err := sm4.NewCipher(key)
if err != nil {
t.Fatal(err)
}
decrypter := cipher.NewECBDecrypter(c)
// test len(src) == 0
decrypter.CryptBlocks(nil, nil)
// cipher: input not full blocks
shouldPanic(t, func() {
decrypter.CryptBlocks(src, src[1:])
})
// cipher: output smaller than input
shouldPanic(t, func() {
decrypter.CryptBlocks(src[1:], src)
})
// cipher: invalid buffer overlap
shouldPanic(t, func() {
decrypter.CryptBlocks(src[1:17], src[2:18])
})
}

76
cipher/example_test.go Normal file
View File

@ -0,0 +1,76 @@
package cipher_test
import (
"crypto/aes"
"encoding/hex"
"fmt"
"github.com/emmansun/gmsm/cipher"
)
func ExampleNewECBEncrypter() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("exampleplaintextexampleplaintext")
// ECB mode works on blocks so plaintexts may need to be padded to the
// next whole block. For an example of such padding, see
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
// assume that the plaintext is already of the correct length.
if len(plaintext)%aes.BlockSize != 0 {
panic("plaintext is not a multiple of the block size")
}
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, len(plaintext))
mode := cipher.NewECBEncrypter(block)
mode.CryptBlocks(ciphertext, plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
fmt.Printf("%x\n", ciphertext)
}
func ExampleNewECBDecrypter() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
ciphertext, _ := hex.DecodeString("f42512e1e4039213bd449ba47faa1b74f42512e1e4039213bd449ba47faa1b74")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// ECB mode always works in whole blocks.
if len(ciphertext)%aes.BlockSize != 0 {
panic("ciphertext is not a multiple of the block size")
}
mode := cipher.NewECBDecrypter(block)
// CryptBlocks can work in-place if the two arguments are the same.
mode.CryptBlocks(ciphertext, ciphertext)
// If the original plaintext lengths are not a multiple of the block
// size, padding would have to be added when encrypting, which would be
// removed at this point. For an example, see
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. However, it's
// critical to note that ciphertexts must be authenticated (i.e. by
// using crypto/hmac) before being decrypted in order to avoid creating
// a padding oracle.
fmt.Printf("%s\n", ciphertext)
// Output: exampleplaintextexampleplaintext
}

View File

@ -1,17 +1,49 @@
package sm4_test
package cipher_test
import (
"bytes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"testing"
"github.com/emmansun/gmsm/internal/cryptotest"
"github.com/emmansun/gmsm/sm4"
)
var sm4GCMTests = []struct {
key, nonce, plaintext, ad, result string
}{
{ // GB/T 36624-2018 C.5 1
"00000000000000000000000000000000",
"000000000000000000000000",
"",
"",
"232f0cfe308b49ea6fc88229b5dc858d",
},
{ // GB/T 15852.3-2019 A.4 GMAC
"feffe9928665731c6d6a8f9467308308",
"cafebabefacedbaddecaf888",
"",
"feedfacedeadbeeffeedfacedeadbeef",
"9d632570f93064264a20918e3081b4cd",
},
{ // GB/T 15852.3-2019 A.4 GMAC
"feffe9928665731c6d6a8f9467308308",
"cafebabefacedbaddecaf888",
"",
"feedfacedeadbeeffeedfacedeadbeefabaddad242831ec2217774244b7221b7",
"1eeaeb669e96bd059bd9929123030e78",
},
{ // GB/T 36624-2018 C.5 2
"00000000000000000000000000000000",
"000000000000000000000000",
"00000000000000000000000000000000",
"",
"7de2aa7f1110188218063be1bfeb6d89b851b5f39493752be508f1bb4482c557",
},
{
"11754cd72aec309bf52f7687212e8957",
"3c819d9a9bed087615030b65",
@ -236,7 +268,7 @@ func TestSM4GCM(t *testing.T) {
// Handle 0 nonce size (expect error and continue)
case len(nonce) == 0:
sm4gcm, err = cipher.NewGCMWithNonceSize(c, 0)
_, err = cipher.NewGCMWithNonceSize(c, 0)
if err == nil {
t.Fatal("expected error for zero nonce size")
}
@ -377,3 +409,65 @@ func TestGCMCounterWrap(t *testing.T) {
}
}
}
func TestSM4GCMRandom(t *testing.T) {
key := []byte("0123456789ABCDEF")
nonce := []byte("0123456789AB")
plaintext := make([]byte, 0x198)
io.ReadFull(rand.Reader, plaintext)
c, err := sm4.NewCipher(key)
if err != nil {
t.Fatal(err)
}
aead, err := cipher.NewGCMWithNonceSize(c, len(nonce))
if err != nil {
t.Fatal(err)
}
got := aead.Seal(nil, nonce, plaintext, nil)
result, err := aead.Open(got[:0], nonce, got, nil)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(result, plaintext) {
t.Error("gcm seal/open 408 bytes fail")
}
}
// Test GCM against the general cipher.AEAD interface tester.
func TestGCMAEAD(t *testing.T) {
minTagSize := 12
for _, keySize := range []int{128} {
// Use AES as underlying block cipher at different key sizes for GCM.
t.Run(fmt.Sprintf("SM4-%d", keySize), func(t *testing.T) {
rng := newRandReader(t)
key := make([]byte, keySize/8)
rng.Read(key)
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
// Test GCM with the current AES block with the standard nonce and tag
// sizes.
cryptotest.TestAEAD(t, func() (cipher.AEAD, error) { return cipher.NewGCM(block) })
// Test non-standard tag sizes.
t.Run("MinTagSize", func(t *testing.T) {
cryptotest.TestAEAD(t, func() (cipher.AEAD, error) { return cipher.NewGCMWithTagSize(block, minTagSize) })
})
// Test non-standard nonce sizes.
for _, nonceSize := range []int{1, 16, 100} {
t.Run(fmt.Sprintf("NonceSize-%d", nonceSize), func(t *testing.T) {
cryptotest.TestAEAD(t, func() (cipher.AEAD, error) { return cipher.NewGCMWithNonceSize(block, nonceSize) })
})
}
})
}
}

306
cipher/hctr.go Normal file
View File

@ -0,0 +1,306 @@
package cipher
import (
"crypto/cipher"
"crypto/subtle"
"errors"
"github.com/emmansun/gmsm/internal/alias"
"github.com/emmansun/gmsm/internal/byteorder"
)
// A LengthPreservingMode represents a block cipher running in a length preserving mode (HCTR,
// HCTR2 etc).
type LengthPreservingMode interface {
// EncryptBytes encrypts a number of plaintext bytes. The length of
// src must be NOT smaller than block size. Dst and src must overlap
// entirely or not at all.
//
// If len(dst) < len(src), EncryptBytes should panic. It is acceptable
// to pass a dst bigger than src, and in that case, Encrypt will
// only update dst[:len(src)] and will not touch the rest of dst.
//
// Multiple calls to EncryptBytes behave NOT same as if the concatenation of
// the src buffers was passed in a single run.
EncryptBytes(dst, src []byte)
// DecryptBytes decrypts a number of ciphertext bytes. The length of
// src must be NOT smaller than block size. Dst and src must overlap
// entirely or not at all.
//
// If len(dst) < len(src), DecryptBytes should panic. It is acceptable
// to pass a dst bigger than src, and in that case, DecryptBytes will
// only update dst[:len(src)] and will not touch the rest of dst.
//
// Multiple calls to DecryptBytes behave NOT same as if the concatenation of
// the src buffers was passed in a single run.
DecryptBytes(dst, src []byte)
// BlockSize returns the mode's block size.
BlockSize() int
}
// hctrFieldElement represents a value in GF(2¹²⁸). In order to reflect the HCTR
// standard and make binary.BigEndian suitable for marshaling these values, the
// bits are stored in big endian order. For example:
//
// the coefficient of x⁰ can be obtained by v.low >> 63.
// the coefficient of x⁶³ can be obtained by v.low & 1.
// the coefficient of x⁶⁴ can be obtained by v.high >> 63.
// the coefficient of x¹²⁷ can be obtained by v.high & 1.
type hctrFieldElement struct {
low, high uint64
}
// reverseBits reverses the order of the bits of 4-bit number in i.
func reverseBits(i int) int {
i = ((i << 2) & 0xc) | ((i >> 2) & 0x3)
i = ((i << 1) & 0xa) | ((i >> 1) & 0x5)
return i
}
// hctrAdd adds two elements of GF(2¹²⁸) and returns the sum.
func hctrAdd(x, y *hctrFieldElement) hctrFieldElement {
// Addition in a characteristic 2 field is just XOR.
return hctrFieldElement{x.low ^ y.low, x.high ^ y.high}
}
// hctrDouble returns the result of doubling an element of GF(2¹²⁸).
func hctrDouble(x *hctrFieldElement) (double hctrFieldElement) {
msbSet := x.high&1 == 1
// Because of the bit-ordering, doubling is actually a right shift.
double.high = x.high >> 1
double.high |= x.low << 63
double.low = x.low >> 1
// If the most-significant bit was set before shifting then it,
// conceptually, becomes a term of x^128. This is greater than the
// irreducible polynomial so the result has to be reduced. The
// irreducible polynomial is 1+x+x^2+x^7+x^128. We can subtract that to
// eliminate the term at x^128 which also means subtracting the other
// four terms. In characteristic 2 fields, subtraction == addition ==
// XOR.
if msbSet {
double.low ^= 0xe100000000000000
}
return
}
// hctrReductionTable is stored irreducible polynomial's double & add precomputed results.
// 0000 - 0
// 0001 - irreducible polynomial >> 3
// 0010 - irreducible polynomial >> 2
// 0011 - (irreducible polynomial >> 3 xor irreducible polynomial >> 2)
// ...
// 1000 - just the irreducible polynomial
var hctrReductionTable = []uint16{
0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0,
0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0,
}
// hctr represents a Variable-Input-Length enciphering mode with a specific block cipher,
// and specific tweak and a hash key. See
// https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.470.5288
// GB/T 17964-2021 第11章 带泛杂凑函数的计数器工作模式
type hctr struct {
cipher cipher.Block
tweak [blockSize]byte
// productTable contains the first sixteen powers of the hash key.
// However, they are in bit reversed order.
productTable [16]hctrFieldElement
}
func (h *hctr) BlockSize() int {
return blockSize
}
// NewHCTR returns a [LengthPreservingMode] which encrypts/decrypts using the given [Block]
// in HCTR mode. The length of tweak and hash key must be the same as the [Block]'s block size.
func NewHCTR(cipher cipher.Block, tweak, hkey []byte) (LengthPreservingMode, error) {
if len(tweak) != blockSize || len(hkey) != blockSize {
return nil, errors.New("cipher: invalid tweak and/or hash key length")
}
c := &hctr{}
c.cipher = cipher
copy(c.tweak[:], tweak)
// We precompute 16 multiples of |key|. However, when we do lookups
// into this table we'll be using bits from a field element and
// therefore the bits will be in the reverse order. So normally one
// would expect, say, 4*key to be in index 4 of the table but due to
// this bit ordering it will actually be in index 0010 (base 2) = 2.
x := hctrFieldElement{
byteorder.BEUint64(hkey[:8]),
byteorder.BEUint64(hkey[8:blockSize]),
}
c.productTable[reverseBits(1)] = x
for i := 2; i < 16; i += 2 {
c.productTable[reverseBits(i)] = hctrDouble(&c.productTable[reverseBits(i/2)])
c.productTable[reverseBits(i+1)] = hctrAdd(&c.productTable[reverseBits(i)], &x)
}
return c, nil
}
// mul sets y to y*H, where H is the GCM key, fixed during NewHCTR.
func (h *hctr) mul(y *hctrFieldElement) {
var z hctrFieldElement
// Eliminate bounds checks in the loop.
_ = hctrReductionTable[0xf]
for i := 0; i < 2; i++ {
word := y.high
if i == 1 {
word = y.low
}
// Multiplication works by multiplying z by 16 and adding in
// one of the precomputed multiples of hash key.
for j := 0; j < 64; j += 4 {
msw := z.high & 0xf
z.high >>= 4
z.high |= z.low << 60
z.low >>= 4
z.low ^= uint64(hctrReductionTable[msw]) << 48
// the values in |table| are ordered for
// little-endian bit positions. See the comment
// in NewHCTR.
t := &h.productTable[word&0xf]
z.low ^= t.low
z.high ^= t.high
word >>= 4
}
}
*y = z
}
func (h *hctr) updateBlock(block []byte, y *hctrFieldElement) {
y.low ^= byteorder.BEUint64(block)
y.high ^= byteorder.BEUint64(block[8:])
h.mul(y)
}
// Universal Hash Function.
// Chapter 3.3 in https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.470.5288.
func (h *hctr) uhash(m []byte, out *[blockSize]byte) {
var y hctrFieldElement
msg := m
// update blocks
for len(msg) >= blockSize {
h.updateBlock(msg, &y)
msg = msg[blockSize:]
}
// update partial block & tweak
if len(msg) > 0 {
var partialBlock [blockSize]byte
copy(partialBlock[:], msg)
copy(partialBlock[len(msg):], h.tweak[:])
h.updateBlock(partialBlock[:], &y)
copy(partialBlock[:], h.tweak[len(msg):])
for i := len(msg); i < blockSize; i++ {
partialBlock[i] = 0
}
h.updateBlock(partialBlock[:], &y)
} else {
h.updateBlock(h.tweak[:], &y)
}
// update bit string length (|M|)₂
y.high ^= uint64(len(m)+blockSize) * 8
h.mul(&y)
// output result
byteorder.BEPutUint64(out[:], y.low)
byteorder.BEPutUint64(out[8:], y.high)
}
func (h *hctr) EncryptBytes(ciphertext, plaintext []byte) {
if len(ciphertext) < len(plaintext) {
panic("cipher: ciphertext is smaller than plaintext")
}
if len(plaintext) < blockSize {
panic("cipher: plaintext length is smaller than the block size")
}
if alias.InexactOverlap(ciphertext[:len(plaintext)], plaintext) {
panic("cipher: invalid buffer overlap")
}
var z1, z2 [blockSize]byte
// a) z1 generation
h.uhash(plaintext[blockSize:], &z1)
subtle.XORBytes(z1[:], z1[:], plaintext[:blockSize])
// b) z2 generation
h.cipher.Encrypt(z2[:], z1[:])
// c) CTR
subtle.XORBytes(z1[:], z1[:], z2[:])
h.ctr(ciphertext[blockSize:], plaintext[blockSize:], &z1)
// d) first ciphertext block generation
h.uhash(ciphertext[blockSize:], &z1)
subtle.XORBytes(ciphertext, z2[:], z1[:])
}
func (h *hctr) DecryptBytes(plaintext, ciphertext []byte) {
if len(plaintext) < len(ciphertext) {
panic("cipher: plaintext is smaller than cihpertext")
}
if len(ciphertext) < blockSize {
panic("cipher: ciphertext length is smaller than the block size")
}
if alias.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) {
panic("cipher: invalid buffer overlap")
}
var z1, z2 [blockSize]byte
// a) z2 generation
h.uhash(ciphertext[blockSize:], &z2)
subtle.XORBytes(z2[:], z2[:], ciphertext[:blockSize])
// b) z1 generation
h.cipher.Decrypt(z1[:], z2[:])
// c) CTR
subtle.XORBytes(z2[:], z2[:], z1[:])
h.ctr(plaintext[blockSize:], ciphertext[blockSize:], &z2)
// d) first plaintext block generation
h.uhash(plaintext[blockSize:], &z2)
subtle.XORBytes(plaintext, z2[:], z1[:])
}
func (h *hctr) ctr(dst, src []byte, baseCtr *[blockSize]byte) {
ctr := make([]byte, blockSize)
num := make([]byte, blockSize)
i := uint64(1)
if concCipher, ok := h.cipher.(concurrentBlocks); ok {
batchSize := concCipher.Concurrency() * blockSize
if len(src) >= batchSize {
var ctrs = make([]byte, batchSize)
for len(src) >= batchSize {
for j := 0; j < concCipher.Concurrency(); j++ {
// (i)₂
byteorder.BEPutUint64(num[blockSize-8:], i)
subtle.XORBytes(ctrs[j*blockSize:], baseCtr[:], num)
i++
}
concCipher.EncryptBlocks(ctrs, ctrs)
subtle.XORBytes(dst, src, ctrs)
src = src[batchSize:]
dst = dst[batchSize:]
}
}
}
for len(src) > 0 {
// (i)₂
byteorder.BEPutUint64(num[blockSize-8:], i)
subtle.XORBytes(ctr, baseCtr[:], num)
h.cipher.Encrypt(ctr, ctr)
n := subtle.XORBytes(dst, src, ctr)
src = src[n:]
dst = dst[n:]
i++
}
}

75
cipher/hctr_test.go Normal file
View File

@ -0,0 +1,75 @@
package cipher_test
import (
"bytes"
"encoding/hex"
"testing"
"github.com/emmansun/gmsm/cipher"
"github.com/emmansun/gmsm/sm4"
)
var hctrSM4TestVectors = []struct {
key string
hashKey string
tweak string
plaintext string
ciphertext string
}{
{
"2B7E151628AED2A6ABF7158809CF4F3C",
"000102030405060708090A0B0C0D0E0F",
"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF",
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c37106bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c37106bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
"8858dda3034233e377936b76ce7edeb6a245075a37800b0b996e8e974c9032ac8de40d90ee4ee5fb58bc10cbc95779485ab38ffb0b4f961d85f086db705ff723edbeaec649b3b406b11b96a418a9c2c51ef41cdd24e472c18336e9efcd07b7e264a1e2d46615198eb74938d72104fa89294a6360cdb6b032a704cf07a087bb2283598552701b2f710d6528d9c3f4dab529afef4413f25169b6cbf8168ccbfa02a2f507513d0cb3802da34dbd928b67e6afc30ca91011070cfd40c2ef3d4ac041",
},
{
"2B7E151628AED2A6ABF7158809CF4F3C",
"000102030405060708090A0B0C0D0E0F",
"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF",
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
"9cd7481d3b7ca904b14b4084d9d4c83ed39eac8e16747895fc2ae1eecd220276af3d0d2f21cb3807561347c81ad138117dd85c652afe16a47dc68eb884068ae3",
},
{
"2B7E151628AED2A6ABF7158809CF4F3C",
"000102030405060708090A0B0C0D0E0F",
"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF",
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417b",
"f7505aff357ac13107cdb2848c6bb2dcdda473f7a6ea939d44f52c986c11ca9341042f2b0091a1ca5c8f708cae8ca6a5c59e2228b3616c4455627722",
},
{
"2B7E151628AED2A6ABF7158809CF4F3C",
"000102030405060708090A0B0C0D0E0F",
"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF",
"6bc1bee22e409f96e93d7e117393172a",
"b7b1dd75f608012dc69621d4ea720a60",
},
}
func TestHCTR(t *testing.T) {
for i, test := range hctrSM4TestVectors {
key1, _ := hex.DecodeString(test.key)
key2, _ := hex.DecodeString(test.hashKey)
tw, _ := hex.DecodeString(test.tweak)
plaintext, _ := hex.DecodeString(test.plaintext)
ciphertext, _ := hex.DecodeString(test.ciphertext)
got := make([]byte, len(plaintext))
c, err := sm4.NewCipher(key1)
if err != nil {
t.Fatal(err)
}
hctr, err := cipher.NewHCTR(c, tw, key2)
if err != nil {
t.Fatal(err)
}
hctr.EncryptBytes(got, plaintext)
if !bytes.Equal(got, ciphertext) {
t.Fatalf("%v case encrypt failed, got %x\n", i+1, got)
}
hctr.DecryptBytes(got, ciphertext)
if !bytes.Equal(got, plaintext) {
t.Fatalf("%v case decrypt failed, got %x\n", i+1, got)
}
}
}

View File

@ -1,10 +1,11 @@
package sm4_test
package cipher_test
import (
"bytes"
"crypto/cipher"
"testing"
"github.com/emmansun/gmsm/internal/cryptotest"
"github.com/emmansun/gmsm/sm4"
)
@ -71,3 +72,19 @@ func TestOFB(t *testing.T) {
}
}
}
func TestOFBStream(t *testing.T) {
t.Run("SM4", func(t *testing.T) {
rng := newRandReader(t)
key := make([]byte, 16)
rng.Read(key)
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
cryptotest.TestStreamFromBlock(t, block, cipher.NewOFB)
})
}

128
cipher/ofbnlf.go Normal file
View File

@ -0,0 +1,128 @@
// Output feedback with a nonlinear function operation mode (OFBNLF mode) in Chinese national standard GB/T 17964-2021.
// See GB/T 17964-2021 Chapter 13.
package cipher
import (
"bytes"
_cipher "crypto/cipher"
"errors"
)
type ofbnlf struct {
cipherFunc CipherCreator
b _cipher.Block
blockSize int
iv []byte
}
func newOFBNLF(cipherFunc CipherCreator, key, iv []byte) (*ofbnlf, error) {
c := &ofbnlf{
cipherFunc: cipherFunc,
}
var err error
c.b, err = cipherFunc(key)
if err != nil {
return nil, err
}
c.blockSize = c.b.BlockSize()
if len(iv) != c.blockSize {
return nil, errors.New("cipher: IV length must equal block size")
}
c.iv = bytes.Clone(iv)
return c, nil
}
type ofbnlfEncrypter ofbnlf
// NewOFBNLFEncrypter returns a BlockMode which encrypts in Output feedback
// with a nonlinear function operation mode, using the given Block.
// The length of iv must be the same as the Block's block size.
func NewOFBNLFEncrypter(cipherFunc CipherCreator, key, iv []byte) (_cipher.BlockMode, error) {
c, err := newOFBNLF(cipherFunc, key, iv)
if err != nil {
return nil, err
}
return (*ofbnlfEncrypter)(c), nil
}
func (x *ofbnlfEncrypter) BlockSize() int { return x.blockSize }
func (x *ofbnlfEncrypter) CryptBlocks(dst, src []byte) {
validate(x.blockSize, dst, src)
iv := x.iv
k := make([]byte, x.blockSize)
for len(src) > 0 {
x.b.Encrypt(k, iv)
c, err := x.cipherFunc(k)
if err != nil {
panic(err)
}
c.Encrypt(dst, src)
src = src[x.blockSize:]
dst = dst[x.blockSize:]
copy(iv, k)
}
// Save the iv for the next CryptBlocks call.
copy(x.iv, iv)
}
func (x *ofbnlfEncrypter) SetIV(iv []byte) {
if len(iv) != len(x.iv) {
panic("cipher: incorrect length IV")
}
copy(x.iv, iv)
}
type ofbnlfDecrypter ofbnlf
// NewOFBNLFDecrypter returns a BlockMode which decrypts in Output feedback
// with a nonlinear function operation mode, using the given Block.
// The length of iv must be the same as the Block's block size and must match
// the iv used to encrypt the data.
func NewOFBNLFDecrypter(cipherFunc CipherCreator, key, iv []byte) (_cipher.BlockMode, error) {
c, err := newOFBNLF(cipherFunc, key, iv)
if err != nil {
return nil, err
}
return (*ofbnlfDecrypter)(c), nil
}
func (x *ofbnlfDecrypter) BlockSize() int { return x.blockSize }
func (x *ofbnlfDecrypter) CryptBlocks(dst, src []byte) {
validate(x.blockSize, dst, src)
if len(src) == 0 {
return
}
iv := x.iv
k := make([]byte, x.blockSize)
for len(src) > 0 {
x.b.Encrypt(k, iv)
c, err := x.cipherFunc(k)
if err != nil {
panic(err)
}
c.Decrypt(dst, src)
src = src[x.blockSize:]
dst = dst[x.blockSize:]
copy(iv, k)
}
// Save the iv for the next CryptBlocks call.
copy(x.iv, iv)
}
func (x *ofbnlfDecrypter) SetIV(iv []byte) {
if len(iv) != len(x.iv) {
panic("cipher: incorrect length IV")
}
copy(x.iv, iv)
}

71
cipher/ofbnlf_test.go Normal file
View File

@ -0,0 +1,71 @@
package cipher_test
import (
"bytes"
"crypto/rand"
"encoding/hex"
"io"
"testing"
"github.com/emmansun/gmsm/cipher"
"github.com/emmansun/gmsm/sm4"
)
var ofbnlfSM4TestVectors = []struct {
key string
iv string
plaintext string
ciphertext string
}{
{
"2B7E151628AED2A6ABF7158809CF4F3C",
"000102030405060708090A0B0C0D0E0F",
"6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710",
"00A5B5C9E645557C20CE7F267736F308A18037828850B9D78883CA622851F86CB7CAEFDFB6D4CABA6AE2D2FCE369CEB31001DD71FDDA9341F8D221CB720FF27B",
},
}
func TestOFBNLF(t *testing.T) {
for i, test := range ofbnlfSM4TestVectors {
key, _ := hex.DecodeString(test.key)
iv, _ := hex.DecodeString(test.iv)
plaintext, _ := hex.DecodeString(test.plaintext)
ciphertext, _ := hex.DecodeString(test.ciphertext)
got := make([]byte, len(plaintext))
encrypter, err := cipher.NewOFBNLFEncrypter(sm4.NewCipher, key, iv)
if err != nil {
t.Fatal(err)
}
encrypter.CryptBlocks(got, plaintext)
if !bytes.Equal(got, ciphertext) {
t.Fatalf("%v case encrypt failed, got %x\n", i+1, got)
}
decrypter, err := cipher.NewOFBNLFDecrypter(sm4.NewCipher, key, iv)
if err != nil {
t.Fatal(err)
}
decrypter.CryptBlocks(got, ciphertext)
if !bytes.Equal(got, plaintext) {
t.Fatalf("%v case decrypt failed, got %x\n", i+1, got)
}
}
}
func TestSM4OFBNLFRandom(t *testing.T) {
key, _ := hex.DecodeString(ofbnlfSM4TestVectors[0].key)
iv := []byte("0123456789ABCDEF")
encrypter, _ := cipher.NewOFBNLFEncrypter(sm4.NewCipher, key, iv)
decrypter, _ := cipher.NewOFBNLFDecrypter(sm4.NewCipher, key, iv)
for i := 1; i <= 50; i++ {
plaintext := make([]byte, i*16)
ciphertext := make([]byte, i*16)
got := make([]byte, i*16)
io.ReadFull(rand.Reader, plaintext)
encrypter.CryptBlocks(ciphertext, plaintext)
decrypter.CryptBlocks(got, ciphertext)
if !bytes.Equal(got, plaintext) {
t.Errorf("test %v blocks failed", i)
}
}
}

13
cipher/stream.go Normal file
View File

@ -0,0 +1,13 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cipher
import "crypto/cipher"
type SeekableStream interface {
cipher.Stream
// XORKeyStreamAt XORs the given src with the key stream at the given offset and writes the result to dst.
XORKeyStreamAt(dst, src []byte, offset uint64)
}

View File

@ -1,249 +1,68 @@
package cipher
import (
_cipher "crypto/cipher"
"encoding/binary"
"errors"
"sync"
"crypto/cipher"
"github.com/emmansun/gmsm/internal/subtle"
"github.com/emmansun/gmsm/internal/xor"
"github.com/emmansun/gmsm/internal/byteorder"
"github.com/emmansun/gmsm/internal/cipher/xts"
)
const GF128_FDBK byte = 0x87
type CipherCreator func([]byte) (_cipher.Block, error)
type concurrentBlocks interface {
Concurrency() int
EncryptBlocks(dst, src []byte)
DecryptBlocks(dst, src []byte)
// NewXTSEncrypter creates a Cipher given a function for creating the underlying
// block cipher (which must have a block size of 16 bytes).
func NewXTSEncrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (cipher.BlockMode, error) {
return xts.NewXTSEncrypter(cipherFunc, key, tweakKey, tweak, false)
}
// A XTSBlockMode represents a block cipher running in a XTS mode
type XTSBlockMode interface {
// BlockSize returns the mode's block size.
BlockSize() int
// Encrypt encrypts or decrypts a number of blocks. The length of
// src must be a multiple of the block size. Dst and src must overlap
// entirely or not at all.
//
Encrypt(dst, src []byte, sectorNum uint64)
// Decrypt decrypts a number of blocks. The length of
// src must be a multiple of the block size. Dst and src must overlap
// entirely or not at all.
//
Decrypt(dst, src []byte, sectorNum uint64)
// NewXTSEncrypterWithSector creates a Cipher given a function for creating the underlying
// block cipher (which must have a block size of 16 bytes) with sector number.
func NewXTSEncrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (cipher.BlockMode, error) {
tweak := make([]byte, blockSize)
byteorder.LEPutUint64(tweak[:8], sectorNum)
return NewXTSEncrypter(cipherFunc, key, tweakKey, tweak)
}
// Cipher contains an expanded key structure. It is safe for concurrent use if
// the underlying block cipher is safe for concurrent use.
type xts struct {
k1, k2 _cipher.Block
// NewGBXTSEncrypter creates a Cipher given a function for creating the underlying
// block cipher (which must have a block size of 16 bytes).
// It follows GB/T 17964-2021.
func NewGBXTSEncrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (cipher.BlockMode, error) {
return xts.NewXTSEncrypter(cipherFunc, key, tweakKey, tweak, true)
}
// blockSize is the block size that the underlying cipher must have. XTS is
// only defined for 16-byte ciphers.
const blockSize = 16
var tweakPool = sync.Pool{
New: func() interface{} {
return new([blockSize]byte)
},
// NewGBXTSEncrypterWithSector creates a Cipher given a function for creating the underlying
// block cipher (which must have a block size of 16 bytes) with sector number.
// It follows GB/T 17964-2021.
func NewGBXTSEncrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (cipher.BlockMode, error) {
tweak := make([]byte, blockSize)
byteorder.LEPutUint64(tweak[:8], sectorNum)
return NewGBXTSEncrypter(cipherFunc, key, tweakKey, tweak)
}
// NewXTS creates a Cipher given a function for creating the underlying
// block cipher (which must have a block size of 16 bytes). The key must be
// twice the length of the underlying cipher's key.
func NewXTS(cipherFunc CipherCreator, key []byte) (XTSBlockMode, error) {
k1, err := cipherFunc(key[:len(key)/2])
if err != nil {
return nil, err
}
k2, err := cipherFunc(key[len(key)/2:])
c := &xts{
k1,
k2,
}
if c.k1.BlockSize() != blockSize {
err = errors.New("xts: cipher does not have a block size of 16")
return nil, err
}
return c, nil
// NewXTSDecrypter creates a Cipher given a function for creating the underlying
// block cipher (which must have a block size of 16 bytes) for decryption.
func NewXTSDecrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (cipher.BlockMode, error) {
return xts.NewXTSDecrypter(cipherFunc, key, tweakKey, tweak, false)
}
func (c *xts) BlockSize() int {
return blockSize
// NewXTSDecrypterWithSector creates a Cipher given a function for creating the underlying
// block cipher (which must have a block size of 16 bytes) with sector number for decryption.
func NewXTSDecrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (cipher.BlockMode, error) {
tweak := make([]byte, blockSize)
byteorder.LEPutUint64(tweak[:8], sectorNum)
return NewXTSDecrypter(cipherFunc, key, tweakKey, tweak)
}
// Encrypt encrypts a sector of plaintext and puts the result into ciphertext.
// Plaintext and ciphertext must overlap entirely or not at all.
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
func (c *xts) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
if len(ciphertext) < len(plaintext) {
panic("xts: ciphertext is smaller than plaintext")
}
if len(plaintext) < blockSize {
panic("xts: plaintext length is smaller than the block size")
}
if subtle.InexactOverlap(ciphertext[:len(plaintext)], plaintext) {
panic("xts: invalid buffer overlap")
}
tweak := tweakPool.Get().(*[blockSize]byte)
for i := range tweak {
tweak[i] = 0
}
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
c.k2.Encrypt(tweak[:], tweak[:])
lastCiphertext := ciphertext
if concCipher, ok := c.k1.(concurrentBlocks); ok {
batchSize := concCipher.Concurrency() * blockSize
var tweaks []byte = make([]byte, batchSize)
for len(plaintext) >= batchSize {
for i := 0; i < concCipher.Concurrency(); i++ {
copy(tweaks[blockSize*i:], tweak[:])
mul2(tweak)
}
xor.XorBytes(ciphertext, plaintext, tweaks)
concCipher.EncryptBlocks(ciphertext, ciphertext)
xor.XorBytes(ciphertext, ciphertext, tweaks)
plaintext = plaintext[batchSize:]
lastCiphertext = ciphertext[batchSize-blockSize:]
ciphertext = ciphertext[batchSize:]
}
}
for len(plaintext) >= blockSize {
xor.XorBytes(ciphertext, plaintext, tweak[:])
c.k1.Encrypt(ciphertext, ciphertext)
xor.XorBytes(ciphertext, ciphertext, tweak[:])
plaintext = plaintext[blockSize:]
lastCiphertext = ciphertext
ciphertext = ciphertext[blockSize:]
mul2(tweak)
}
// is there a final partial block to handle?
if remain := len(plaintext); remain > 0 {
var x [blockSize]byte
//Copy the final ciphertext bytes
copy(ciphertext, lastCiphertext[:remain])
//Copy the final plaintext bytes
copy(x[:], plaintext)
//Steal ciphertext to complete the block
copy(x[remain:], lastCiphertext[remain:blockSize])
//Merge the tweak into the input block
xor.XorBytes(x[:], x[:], tweak[:])
//Encrypt the final block using K1
c.k1.Encrypt(x[:], x[:])
//Merge the tweak into the output block
xor.XorBytes(lastCiphertext, x[:], tweak[:])
}
tweakPool.Put(tweak)
// NewGBXTSDecrypter creates a Cipher given a function for creating the underlying
// block cipher (which must have a block size of 16 bytes) for decryption.
// It follows GB/T 17964-2021.
func NewGBXTSDecrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (cipher.BlockMode, error) {
return xts.NewXTSDecrypter(cipherFunc, key, tweakKey, tweak, true)
}
// Decrypt decrypts a sector of ciphertext and puts the result into plaintext.
// Plaintext and ciphertext must overlap entirely or not at all.
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
func (c *xts) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
if len(plaintext) < len(ciphertext) {
panic("xts: plaintext is smaller than ciphertext")
}
if len(ciphertext) < blockSize {
panic("xts: ciphertext length is smaller than the block size")
}
if subtle.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) {
panic("xts: invalid buffer overlap")
}
tweak := tweakPool.Get().(*[blockSize]byte)
for i := range tweak {
tweak[i] = 0
}
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
c.k2.Encrypt(tweak[:], tweak[:])
if concCipher, ok := c.k1.(concurrentBlocks); ok {
batchSize := concCipher.Concurrency() * blockSize
var tweaks []byte = make([]byte, batchSize)
for len(ciphertext) >= batchSize {
for i := 0; i < concCipher.Concurrency(); i++ {
copy(tweaks[blockSize*i:], tweak[:])
mul2(tweak)
}
xor.XorBytes(plaintext, ciphertext, tweaks)
concCipher.DecryptBlocks(plaintext, plaintext)
xor.XorBytes(plaintext, plaintext, tweaks)
plaintext = plaintext[batchSize:]
ciphertext = ciphertext[batchSize:]
}
}
for len(ciphertext) >= 2*blockSize {
xor.XorBytes(plaintext, ciphertext, tweak[:])
c.k1.Decrypt(plaintext, plaintext)
xor.XorBytes(plaintext, plaintext, tweak[:])
plaintext = plaintext[blockSize:]
ciphertext = ciphertext[blockSize:]
mul2(tweak)
}
if remain := len(ciphertext); remain >= blockSize {
var x [blockSize]byte
if remain > blockSize {
var tt [blockSize]byte
copy(tt[:], tweak[:])
mul2(&tt)
xor.XorBytes(x[:], ciphertext, tt[:])
c.k1.Decrypt(x[:], x[:])
xor.XorBytes(plaintext, x[:], tt[:])
//Retrieve the length of the final block
remain -= blockSize
//Copy the final plaintext bytes
copy(plaintext[blockSize:], plaintext)
//Copy the final ciphertext bytes
copy(x[:], ciphertext[blockSize:])
//Steal ciphertext to complete the block
copy(x[remain:], plaintext[remain:blockSize])
} else {
//The last block contains exactly 128 bits
copy(x[:], ciphertext)
}
xor.XorBytes(x[:], x[:], tweak[:])
c.k1.Decrypt(x[:], x[:])
xor.XorBytes(plaintext, x[:], tweak[:])
}
tweakPool.Put(tweak)
}
// mul2 multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
// x¹²⁸ + x⁷ + x² + x + 1.
func mul2(tweak *[blockSize]byte) {
var carryIn byte
for j := range tweak {
carryOut := tweak[j] >> 7
tweak[j] = (tweak[j] << 1) + carryIn
carryIn = carryOut
}
if carryIn != 0 {
// If we have a carry bit then we need to subtract a multiple
// of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
// By dropping the carry bit, we're subtracting the x^128 term
// so all that remains is to subtract x⁷ + x² + x + 1.
// Subtraction (and addition) in this representation is just
// XOR.
tweak[0] ^= GF128_FDBK // 1<<7 | 1<<2 | 1<<1 | 1
}
// NewGBXTSDecrypterWithSector creates a Cipher given a function for creating the underlying
// block cipher (which must have a block size of 16 bytes) with sector number for decryption.
// It follows GB/T 17964-2021.
func NewGBXTSDecrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (cipher.BlockMode, error) {
tweak := make([]byte, blockSize)
byteorder.LEPutUint64(tweak[:8], sectorNum)
return NewGBXTSDecrypter(cipherFunc, key, tweakKey, tweak)
}

229
cipher/xts_sm4_test.go Normal file
View File

@ -0,0 +1,229 @@
package cipher_test
import (
"bytes"
"encoding/hex"
"testing"
"github.com/emmansun/gmsm/cipher"
"github.com/emmansun/gmsm/sm4"
)
var xtsTestVectors = []struct {
key string
sector uint64
plaintext string
ciphertext string
}{
{ // XTS-SM4-128 applied for a data unit of 32 bytes
"0000000000000000000000000000000000000000000000000000000000000000",
0,
"0000000000000000000000000000000000000000000000000000000000000000",
"d9b421f731c894fdc35b77291fe4e3b02a1fb76698d59f0e51376c4ada5bc75d",
}, {
"1111111111111111111111111111111122222222222222222222222222222222",
0x3333333333,
"4444444444444444444444444444444444444444444444444444444444444444",
"a74d726c11196a32be04e001ff29d0c7932f9f3ec29bfcb64dd17f63cbd3ea31",
}, {
"fffefdfcfbfaf9f8f7f6f5f4f3f2f1f022222222222222222222222222222222",
0x3333333333,
"4444444444444444444444444444444444444444444444444444444444444444",
"7f76088effadf70c02ea9f95da0628d351bfcb9eac0563bcf17b710dab0a9826",
}, { // XTS-SM4-128 applied for a data unit of 512 bytes
"2718281828459045235360287471352631415926535897932384626433832795",
0,
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
"54dd65b6326faea8fad1a83c63614af39f721d8dfe177a30b66abf6a449980e1cdbe06afb73336f37a4d39de964a30d7d04a3799169c60258f6b748a61861aa5ec92a2c15b2b7c615a42aba499bbd6b71db9c789b2182089a25dd3df800ed1864d19f7ed45fd17a9480b0fb82d9b7fc3ed57e9a1140eaa778dd2dd679e3edc3dc4d55c950ebc531d9592f7c4638256d56518292a20af98fdd3a63600350a70ab5a40f4c285037ca01f251f19ecae0329ff77ad88cd5a4cdea2aeabc22148ffbd239bd10515bde1131dec8404e443dc763140d5f22bf33e0c6872d6b81d630f6f00cdd058fe80f9cbfb77707f93cee2ca92b915b8304027c190a84e2d65e018cc6a387d3766acdb28253284e8db9acf8f52280ddc6d0033d2ccaaa4f9aeff123669bc024fd6768edf8bc1f8d622c19c609ef97f609190cd110241e7fb084ed8942da1f9b9cf1b514b61a388b30ea61a4a745b381ee7ad6c4db1275453b8413f98df6e4a40986ee4b59af5dfaecd301265179067a00d7ca35ab95abd617adea28ec1c26a97de28b8bfe30120d6aefbd258c59e42d161e8065a78106bdca5cd90fb3aac4e93866c8a7f9676860a79145bd92e02e819a90be0b97cc522b32106856fdf0e54d88e4624155a2f1c14eaeaa163f858e99a806e791acd82f1b0e29f0028a4c38e976f571a93f4fd57d787c24db0e01ca304e5a5c4dd50cf8bdbf491e57c",
}, { // Vector 5
"2718281828459045235360287471352631415926535897932384626433832795",
1,
"27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89cc78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad02655ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f4341332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203ebb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18deb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568",
"0e36ba273dd121afc77e0d8c00aa4a662b21f363470d333f2fe2ddcbcc51ecd523022f5fa7970062800cd3859cacead369263681543db431f3844a3638e837cf025cecc3b778e14ac1fd02bb684d0e3cc3d05758cf4b3827bae92f9f09a45487e0a830154a4206a14c4077bcc928e6039b78cdf8f915236c5a4efc21a0ba7173232cef6f18f8b53be5e1eb37282bed31a24f322cf1bba02dfd2583ce216a73726915116fd8ce46d58aa562b5a5d88076792d6e35cba40552db6a19776eaf255c3fc927adc41cb83a83884f98176267f37e543ce34fa32960d1d05aa05ff04103037a730175f1d59a32b64f308925fc9fa9c60421b4ab438e14504227cba20c8c06b508554fb02e52b92a1cd0a8e386511bc4c2fb62998d0ac5d9e7614080a10039b8cddf24a644b3e0aa02bb5d6c0897a84bfe0d12690cbd9fb92fd39b5b9504deeeaab0c5b9839b6283b87abe6439d28f0afb0508104fd4db9fd6e0301c6a488e76fd2a4801d2b7df57e0179506e9a8dbd7312be3922ea4e7339227061485452296dabc3b0f178a2e4ba012bbb6e836dec5d25abaa0f399ca622c5f075dfae7b2ffef4e396cd74b9bc3aeb7c212a5fd5c42b73fcf92e1f4ca458bb50e7257c4ffea253f30f7eaf9a6762ce15177f55ba250a4293d6ecdbd2e9a80c942b38dbdbd74773245a7a7db6b91d1f6c74bd32b7a7a193a2d260d266b64dd19b959ae42",
}, { // XTS-SM4-128 applied for a data unit that is not a multiple of 16 bytes, but should be a complte byte
"c46acc2e7e013cb71cdbf750cf76b000249fbf4fb6cd17607773c23ffa2c4330",
94,
"7e9c2289cba460e470222953439cdaa892a5433d4dab2a3f67",
"c3cf5445c64aa518f4abce2848faddfb4605d9fb66f1f12c0c",
}, {
"56ffcc9bbbdf413f0fc0f888f44b7493bb1925a39b8adf02d9009bb16db0a887",
144,
"9a839cc14363bafcfc0cc93b14f8e769d35b94cc98267438e3",
"af027012c829206c32a31706999d046f10a83bcacbc5c96353",
},
{
"7454a43b87b1cf0dec95032c22873be3cace3bb795568854c1a008c07c5813f3",
108,
"41088fa15195b2733fe824d2c1fdc8306080863945fb2a73cf",
"614ee9311a53791889338eb2f66fedff7dc15126349bed1465",
},
}
func fromHex(s string) []byte {
ret, err := hex.DecodeString(s)
if err != nil {
panic("xts: invalid hex in test")
}
return ret
}
func TestXTS(t *testing.T) {
for i, test := range xtsTestVectors {
key := fromHex(test.key)
encrypter, err := cipher.NewXTSEncrypterWithSector(sm4.NewCipher, key[:len(key)/2], key[len(key)/2:], test.sector)
if err != nil {
t.Errorf("#%d: failed to create encrypter: %s", i, err)
continue
}
decrypter, err := cipher.NewXTSDecrypterWithSector(sm4.NewCipher, key[:len(key)/2], key[len(key)/2:], test.sector)
if err != nil {
t.Errorf("#%d: failed to create decrypter: %s", i, err)
continue
}
plaintext := fromHex(test.plaintext)
ciphertext := make([]byte, len(plaintext))
encrypter.CryptBlocks(ciphertext, plaintext)
expectedCiphertext := fromHex(test.ciphertext)
if !bytes.Equal(ciphertext, expectedCiphertext) {
t.Errorf("#%d: encrypted failed, got: %x, want: %x", i, ciphertext, expectedCiphertext)
continue
}
decrypted := make([]byte, len(ciphertext))
decrypter.CryptBlocks(decrypted, ciphertext)
if !bytes.Equal(decrypted, plaintext) {
t.Errorf("#%d: decryption failed, got: %x, want: %x", i, decrypted, plaintext)
}
}
}
// Test data is from GB/T 17964-2021 B.7
var xtsGBTestVectors = []struct {
key string
tweak string
plaintext string
ciphertext string
}{
{
"2B7E151628AED2A6ABF7158809CF4F3C000102030405060708090A0B0C0D0E0F",
"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF",
"6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17",
"E9538251C71D7B80BBE4483FEF497BD12C5C581BD6242FC51E08964FB4F60FDB0BA42F63499279213D318D2C11F6886E903BE7F93A1B3479",
},
}
func TestGBXTSSample(t *testing.T) {
for i, test := range xtsGBTestVectors {
key := fromHex(test.key)
tweak := fromHex(test.tweak)
encrypter, err := cipher.NewGBXTSEncrypter(sm4.NewCipher, key[:len(key)/2], key[len(key)/2:], tweak)
if err != nil {
t.Errorf("#%d: failed to create encrypter: %s", i, err)
continue
}
decrypter, err := cipher.NewGBXTSDecrypter(sm4.NewCipher, key[:len(key)/2], key[len(key)/2:], tweak)
if err != nil {
t.Errorf("#%d: failed to create decrypter: %s", i, err)
continue
}
plaintext := fromHex(test.plaintext)
ciphertext := make([]byte, len(plaintext))
encrypter.CryptBlocks(ciphertext, plaintext)
expectedCiphertext := fromHex(test.ciphertext)
if !bytes.Equal(ciphertext, expectedCiphertext) {
t.Errorf("#%d: encrypted failed, got: %x, want: %x", i, ciphertext, expectedCiphertext)
continue
}
decrypted := make([]byte, len(ciphertext))
decrypter.CryptBlocks(decrypted, ciphertext)
if !bytes.Equal(decrypted, plaintext) {
t.Errorf("#%d: decryption failed, got: %x, want: %x", i, decrypted, plaintext)
}
}
}
var gbXtsTestVectors = []struct {
key string
sector uint64
plaintext string
ciphertext string
}{
{ // XTS-SM4-128 applied for a data unit of 32 bytes
"0000000000000000000000000000000000000000000000000000000000000000",
0,
"0000000000000000000000000000000000000000000000000000000000000000",
"d9b421f731c894fdc35b77291fe4e3b0e58e55e613a862b4d2b0f1073b4b4fd0",
}, {
"1111111111111111111111111111111122222222222222222222222222222222",
0x3333333333,
"4444444444444444444444444444444444444444444444444444444444444444",
"a74d726c11196a32be04e001ff29d0c7724feef81d666ae5afdfe4649544fcf5",
}, {
"fffefdfcfbfaf9f8f7f6f5f4f3f2f1f022222222222222222222222222222222",
0x3333333333,
"4444444444444444444444444444444444444444444444444444444444444444",
"7f76088effadf70c02ea9f95da0628d3ef2d6a77004beaa9016001d6789dd5a0",
}, { // XTS-SM4-128 applied for a data unit of 512 bytes
"2718281828459045235360287471352631415926535897932384626433832795",
0,
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
"54dd65b6326faea8fad1a83c63614af398bddb6824735dab93ec4e75734215d463f67daf53742fb2a2847d5fde3984f8882cfd5fa9d6642e1e871c155202440044251465211628ba86f8d2998387a685edde23c07610b7388aab17f205aa5dada33c0a8a4225bc114254c796f800c638e016d199cd21dc28e92dc2b8587545509a8e1d659c596d3f6c8c225a27bdb2b02fe5a0c0183a592b396d32765fe733afb438a6ffb305ae1377c56d872badcebbd37812ff79f0571b3f977537570a1f76b9a50c49ab8d867fa024ea4483a25f7947b07885bb839e777abe76af11adf3108d1195933f96b7949b0664bdb89beb3bc48fb5f5d2109d32332f17c9a6ddea55441d1bbf43280ec7e75791e234d651a0716209eb21ae06061e33a72b0c530cb15fe0b55016b188dad75c4c50232dce1f5df61911c79bee60397b64bb914c0f26efcfb6ffab2bb33bdfd8db98c44debbd4ca865d41cbe1d0801b01aba2603cbea599b32c836789deeb9a3c18f3cae977b42ec81f1dfef6e098dd9e9dd6c1822bb938b08641bb72461f8d38c1724a43ae1254b9223e2270cf9f7d71a6bf093df2079fd2cc2fe87e846d799de30483f80164c31e65d8aae5f72d6dc71118932a008df547c712bee45ddebcdce098d673ef5ede91edfd45d17cb90963d3e2e2e2508a376a7b1af4d69e756ea5df52ac440791d57d56b5e057ad00e077d2df5009416",
}, { // Vector 5
"2718281828459045235360287471352631415926535897932384626433832795",
1,
"27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89cc78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad02655ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f4341332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203ebb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18deb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568",
"0e36ba273dd121afc77e0d8c00aa4a665f801f3607af61b61058b2f5d007310822200eaaeef759d515ebd032dad4235f5cd2dc735b57b56e003bce3f56890618877db69aa4519edcf681c6fc19c9c4a5655372d1549148c759efba00140275b46b6a5f6522de1702c48ff209a1dd7d1f56e775252796a09c20f903bfb3935bc79c0cdcaa9d2f30e616160e0662fb35311676e86e18d7d90d4203bc6862a9187b8657162143ce914750a86f984cf660311917e00fcf450ee188f088b4222522276bf3391e94de4fdad4134dfc7d08113c65e1b103bd3ad75fb13bba7f842451f9023ed21f1d23bc1c57d593932e021548bbff61ea9a24f359b4f7a8f2a998587495b726411f84734b189f65c4e79f09c7875f9c924b32e5bf2785a9935854e08ce86f5a4a399af6731099a13e10db0b32b888865b4416d69014a8cdb28b3912ec0b832835df7b59637d0687747815ba7cf9efae862dd6e80763acb50898fe1b3ba13a39d81b20d6d50613fbb5fbdcae2a7a87b9377eec455a8bae5102d5e6a7bea9b6b77d3f9895b277a55a524721cd0e59ce35e915de622480c5e0d31d153282dd832278fd2b795933f5dc591c17bd6d7f38fcd6afce551e8485109673881519d2845395ce9ceaea6306e38a73f9bb990931323a3136d18ee76c3e727cfb07cf386519313e1c44adcc50ae79bfac6952e3b98948206fb3dc3ebaed556bf27f16",
}, { // XTS-SM4-128 applied for a data unit that is not a multiple of 16 bytes, but should be a complte byte
"c46acc2e7e013cb71cdbf750cf76b000249fbf4fb6cd17607773c23ffa2c4330",
94,
"7e9c2289cba460e470222953439cdaa892a5433d4dab2a3f67",
"4d5501ea41cf6b6532b4b7129c6f6ee74605d9fb66f1f12c0c",
}, {
"56ffcc9bbbdf413f0fc0f888f44b7493bb1925a39b8adf02d9009bb16db0a887",
144,
"9a839cc14363bafcfc0cc93b14f8e769d35b94cc98267438e3",
"f04f3f16b354cccdc39fc664ec7f8db010a83bcacbc5c96353",
},
{
"7454a43b87b1cf0dec95032c22873be3cace3bb795568854c1a008c07c5813f3",
108,
"41088fa15195b2733fe824d2c1fdc8306080863945fb2a73cf",
"791a9469ed5a22d8195ac37c43c1b0377dc15126349bed1465",
},
}
func TestGBXTS(t *testing.T) {
for i, test := range gbXtsTestVectors {
key := fromHex(test.key)
encrypter, err := cipher.NewGBXTSEncrypterWithSector(sm4.NewCipher, key[:len(key)/2], key[len(key)/2:], test.sector)
if err != nil {
t.Errorf("#%d: failed to create encrypter: %s", i, err)
continue
}
decrypter, err := cipher.NewGBXTSDecrypterWithSector(sm4.NewCipher, key[:len(key)/2], key[len(key)/2:], test.sector)
if err != nil {
t.Errorf("#%d: failed to create decrypter: %s", i, err)
continue
}
plaintext := fromHex(test.plaintext)
ciphertext := make([]byte, len(plaintext))
encrypter.CryptBlocks(ciphertext, plaintext)
expectedCiphertext := fromHex(test.ciphertext)
if !bytes.Equal(ciphertext, expectedCiphertext) {
t.Errorf("#%d: encrypted failed, got: %x, want: %x", i, ciphertext, expectedCiphertext)
continue
}
decrypted := make([]byte, len(ciphertext))
decrypter.CryptBlocks(decrypted, ciphertext)
if !bytes.Equal(decrypted, plaintext) {
t.Errorf("#%d: decryption failed, got: %x, want: %x", i, decrypted, plaintext)
}
}
}

View File

@ -1,14 +1,15 @@
package cipher
package cipher_test
import (
"bytes"
"crypto/aes"
"encoding/hex"
"testing"
"github.com/emmansun/gmsm/cipher"
)
// These test vectors have been taken from IEEE P1619/D16, Annex B.
var xtsTestVectors = []struct {
var xtsAesTestVectors = []struct {
key string
sector uint64
plaintext string
@ -63,51 +64,56 @@ var xtsTestVectors = []struct {
},
}
func fromHex(s string) []byte {
ret, err := hex.DecodeString(s)
if err != nil {
panic("xts: invalid hex in test")
}
return ret
}
func TestXTSWithAES(t *testing.T) {
for i, test := range xtsAesTestVectors {
key := fromHex(test.key)
func TestXTS(t *testing.T) {
for i, test := range xtsTestVectors {
c, err := NewXTS(aes.NewCipher, fromHex(test.key))
encrypter, err := cipher.NewXTSEncrypterWithSector(aes.NewCipher, key[:len(key)/2], key[len(key)/2:], test.sector)
if err != nil {
t.Errorf("#%d: failed to create cipher: %s", i, err)
t.Errorf("#%d: failed to create encrypter: %s", i, err)
continue
}
decrypter, err := cipher.NewXTSDecrypterWithSector(aes.NewCipher, key[:len(key)/2], key[len(key)/2:], test.sector)
if err != nil {
t.Errorf("#%d: failed to create decrypter: %s", i, err)
continue
}
plaintext := fromHex(test.plaintext)
ciphertext := make([]byte, len(plaintext))
c.Encrypt(ciphertext, plaintext, test.sector)
copy(ciphertext, plaintext)
encrypter.CryptBlocks(ciphertext, ciphertext)
expectedCiphertext := fromHex(test.ciphertext)
if !bytes.Equal(ciphertext, expectedCiphertext) {
t.Errorf("#%d: encrypted failed, got: %x, want: %x", i, ciphertext, expectedCiphertext)
continue
}
decrypted := make([]byte, len(ciphertext))
c.Decrypt(decrypted, ciphertext, test.sector)
if !bytes.Equal(decrypted, plaintext) {
t.Errorf("#%d: decryption failed, got: %x, want: %x", i, decrypted, plaintext)
decrypter.CryptBlocks(ciphertext, ciphertext)
if !bytes.Equal(ciphertext, plaintext) {
t.Errorf("#%d: decryption failed, got: %x, want: %x", i, ciphertext, plaintext)
}
}
}
func TestShorterCiphertext(t *testing.T) {
c, err := NewXTS(aes.NewCipher, make([]byte, 32))
encrypter, err := cipher.NewXTSEncrypterWithSector(aes.NewCipher, make([]byte, 16), make([]byte, 16), 0)
if err != nil {
t.Fatalf("NewCipher failed: %s", err)
t.Fatalf("NewXTSEncrypterWithSector failed: %s", err)
}
decrypter, err := cipher.NewXTSDecrypterWithSector(aes.NewCipher, make([]byte, 16), make([]byte, 16), 0)
if err != nil {
t.Fatalf("NewXTSDecrypterWithSector failed: %s", err)
}
plaintext := make([]byte, 32)
encrypted := make([]byte, 48)
decrypted := make([]byte, 48)
c.Encrypt(encrypted, plaintext, 0)
c.Decrypt(decrypted, encrypted[:len(plaintext)], 0)
encrypter.CryptBlocks(encrypted, plaintext)
decrypter.CryptBlocks(decrypted, encrypted[:len(plaintext)])
if !bytes.Equal(plaintext, decrypted[:len(plaintext)]) {
t.Errorf("En/Decryption is not inverse")

112
docs/cfca.md Normal file
View File

@ -0,0 +1,112 @@
# CFCA互操作性指南
这是一份**不完整**的CFCA互操作性指南。
## 什么是CFCA
CFCA是中国金融认证中心的英文缩写。
## 什么是SADK
SADKSecurity Application Development Kit是CFCA推出的一套支持全平台、全浏览器、多语言的安全应用开发套件。实现了证书下载、证书应用过程中的全业务功能覆盖可与客户业务系统、CFCA RA、CA、统一下载平台无缝对接为用户提供证书下载、证书更新、签名验签、加密解密等全方位的数字证书安全服务。具体说明请参考[数字证书安全应用开发套件SADK](https://www.cfca.com.cn/20150807/101228565.html)。
其JAVA版本(其它语言版本未知)基本上是一个基于[Bouncy Castle](https://www.bouncycastle.org/)的实现当然它看起来也支持JNI接入OpenSSL、U盾
## 为什么会有互操作性问题
* CFCA有一些实现没有相关标准。
* SADK存在较早可能有些实现早于标准发布。
* SADK版本较多不同版本也会有互操作性兼容问题。
* 其它未知原因。
因为我也找不到SADK的版本历史或者Change Log这里只是根据有限资料的一些判断。
## 容易出现互操作性问题的功能
相对而言互操作性问题主要出现在SM2椭圆曲线公钥密码算法应用上特别是加解密、数字信封加解密上。
### SM2加解密
加解密算法实现部分没有什么互操作性问题,主要是密文格式问题。
#### SADK 3.2之前版本
由于没有版本历史,所以这里只是大致推测(如果有不准确之处,敬请指出)。
SADK 3.2之前的版本只支持C1C2C3密文格式而且C1只支持非压缩点格式且输出忽略0x04这个点非压缩标识。
| 随机点 | 密文 | SM3哈希值 |
| :--- | :--- | :--- |
| C1 (64 bytes) | C2 | C3 (32 bytes) |
所以如果和SADK 3.2之前的应用交互加密输出格式只能选C1C2C3且密文通过切片操作忽略首字节0x04这个点非压缩标识反之如果是解密SADK 3.2之前的应用提供的密文则要指定C1C2C3格式同时自己在密文前添加0x04这个点非压缩标识。**互操作的重要前提是知道对方的密文格式**。
#### SADK 3.2+版本
SADK 3.2之后的版本支持下列SM2密文格式(encryptedType)
| encryptedType | 输出格式 | 用本软件库如何解密 |
| :--- | :--- | :--- |
| 0 | ASN.1编码格式 ```EncryptUtil.encrypt``` 方法默认 | 正常解密 |
| 2 | C1C3C2 格式带0x04这个点非压缩标识 | 正常解密 |
| 4 | C1C3C2 格式不带0x04这个点非压缩标识 ```EncryptUtil.encryptMessageBySM2 / EncryptUtil.encryptFileBySM2``` 方法默认) | 添加0x04前缀后解密 |
| 8 | C1C2C3 格式带0x04这个点非压缩标识 | 指定解密Opts后解密 |
| 16 | C1C2C3 格式不带0x04这个点非压缩标识 | 添加0x04前缀同时指定解密Opts后解密 |
**SADK 3.2之后的版本,解密过程**
1. 先尝试是否ASN.1格式,如果是,就解密;否则,
2. 当**C1C3C2不带0x04这个点非压缩标识**的格式处理,如果解密成功,则结束;否则,
3. 当**C1C2C3不带0x04这个点非压缩标识**的格式处理。
从这个解密流程来看SADK 3.2+可以解密 SADK 3.2之前的SM2密文反之不行。
所以如果和SADK 3.2之后的应用交互加密输出格式可以是ASN.1编码格式或者是不带0x04这个点非压缩标识的C1C3C2/C1C2C3格式反之如果是解密使用SADK 3.2+的应用提供的密文则要先区分是否是ASN.1格式是的话就比较简单不是的话则要指定C1C3C2格式同时自己在密文前添加0x04这个点非压缩标识。**互操作的重要前提是知道对方的密文格式**。
### SM2数字信封加解密
互操作性问题主要出在:
1. 数据对称加密所用密钥的SM2密文格式。
2. 对称加密算法的OID。```public static final ASN1ObjectIdentifier id_sm4_CBC = new ASN1ObjectIdentifier("1.2.156.10197.1.104");```。
3. 如果需要用本软件库去解密CFCA生成的SM2数字信封目前会有问题从**v0.29.3**开始可以解密。CFCA实现不符合《GB/T 35275-2017信息安全技术 SM2密码算法加密签名消息语法规范》它的**RecipientInfo**默认使用SubjectKeyIdentifier而不是IssuerAndSerialNumber。在SADK 3.7.1.0中需要指定recipientPolicyType=20从证书扩展中获取SubjectKeyID找不到抛异常1根据公钥数据直接计算SubjectKeyID2使用证书的IssuerAndSerialNumber才会使用IssuerAndSerialNumber。正常情况下只有CA证书才一定会在证书扩展中有SubjectKeyID信息。如果要产生和CFCA一样的加密信封请使用```pkcs7.EnvelopeMessageCFCA```方法。
**v0.29.6**之后,请直接使用
* `cfca.EnvelopeMessage`
* `cfca.OpenEnvelopedMessage`
* `cfca.EnvelopeMessageLegacy`
* `cfca.OpenEnvelopedMessageLegacy`
#### SADK 3.2之前版本
1. 数据对称加密密钥的密文格式为**C1C2C3 格式不带0x04这个点非压缩标识**。这个不符合《GM/T 0010-2012 SM2密码算法加密签名消息语法规范》以及《GB/T 35275-2017 信息安全技术 SM2密码算法加密签名消息语法规范》。
2. SM4-CBC的OID使用了["SM4" block cipher](https://oid-rep.orange-labs.fr/get/1.2.156.10197.1.104),而不是["SMS4-CBC"](https://oid-rep.orange-labs.fr/get/1.2.156.10197.1.104.2)。
本软件库的```pkcs7.EncryptCFCA```方法```DecryptCFCA```方法提供了SADK 3.2之前版本的信封加解密兼容性记得cipher参数选择```pkcs.SM4```。但是```pkcs7.EncryptCFCA```方法产生的加密信封依然使用IssuerAndSerialNumber作为RecipientInfo。
#### SADK 3.2+版本
1. 数据对称加密密钥的密文格式为**ASN.1编码格式**这个符合《GB/T 35275-2017 信息安全技术 SM2密码算法加密签名消息语法规范》。
2. SM4-CBC的OID使用了["SM4" block cipher](https://oid-rep.orange-labs.fr/get/1.2.156.10197.1.104),而不是["SMS4-CBC"](https://oid-rep.orange-labs.fr/get/1.2.156.10197.1.104.2)。
本软件库的```pkcs7.EncryptSM```方法```Decrypt```方法提供了SADK 3.2+版本的信封加解密兼容性。使用时,请确保`cipher`参数选择```pkcs.SM4```。```pkcs7.EncryptSM```方法符合《GB/T 35275-2017 信息安全技术 SM2密码算法加密签名消息语法规范》CFCA的SADK可实现相应数据的解密。
本软件库的```pkcs7.EnvelopeMessageCFCA```方法提供了CFCA SADK更兼容的实现也就是recipientPolicyType=0。
从SADK 的向下兼容性来看SADK 3.2+能够解密SADK 3.2之前版本的数字信封加密数据,反之不行。
### SM2 PKCS7签名数据
```cfca.sadk.util.p7SignMessageAttach / cfca.sadk.util.p7SignMessageDetach```,对应```pkcs7.SignWithoutAttr```如果要Detach签名调用```Finish```之前调用```Detach```就行。
```cfca.sadk.util.p7SignFileAttach / cfca.sadk.util.p7SignFileDetach```类似,只是本软件库不提供对应方法,您可以通过```pkcs7.SignWithoutAttr```自己实现。
参考[cfca sadk 3.0.2.0](https://github.com/emmansun/gmsm/issues/260)
**v0.29.6**之后,请直接使用
* `cfca.SignMessageAttach`
* `cfca.VerifyMessageAttach`
* `cfca.SignMessageDetach`
* `cfca.VerifyMessageDetach`
* `cfca.SignDigestDetach`
* `cfca.VerifyDigestDetach`
### 解密时自动检测?
要穷举、尝试所有可能的密文格式不是不可以但这会或多或少地影响解密的性能。你要和对方集成还是知己知彼比较好对于加解密来说对用户透明不代表是好事。本软件库的SM2解密也实现了一定的自动检测通过首字节判断基于首字节只有固定那几个的假设
* 0x30 - ASN.1格式。
* 0x04 - C1为非压缩点格式具体是C1C3C2还是C1C2C3取决于解密时的选项参数默认为C1C3C2。
* 0x02/0x03 - C1为压缩点格式具体是C1C3C2还是C1C2C3取决于解密时的选项参数默认为C1C3C2。
### 生成双密钥CSR v0.29.6+
`cfca.CreateCertificateRequest`和CFCA SADK不同调用者需要自行先生成两对密钥对一对用于签名证书一对用于加解密CFCA生成的加密用私钥文件CFCA加密申请者解密。这个方法对应CFCA的`cfca.sadk.util.P10Request.generateDoublePKCS10Request`方法。按我的理解非国密RSA应该不需要支持这种双密钥对机制不过既然**CFCA SADK**支持,本软件库从**v0.30.0**开始也支持。
使用`cfca.ParseEscrowPrivateKey`解析CFCA返回的加密用私钥。
### SM2私钥、证书的解析
这个是CFCA自定义的未见相关标准可以通过```cfca.ParseSM2```来解析。```cfca.ParseSM2```函数只接受**DER**编码的二进制数据,如果你的数据是**base64**编码的,请先自行解码。

186
docs/pkcs12.md Normal file
View File

@ -0,0 +1,186 @@
# [go-pkcs12](https://github.com/emmansun/go-pkcs12)应用指南
[PKCS #12: Personal Information Exchange Syntax v1.1](https://datatracker.ietf.org/doc/html/rfc7292)PKCS12目前似乎没有相应的国密标准。
定制PKCS12的目的是
1. 可以处理**SM2**私钥和证书。
2. 可以替代、使用一些商密算法,主要是**SM3**和**SM4**。
## PKCS#12的解析
[go-pkcs12](https://github.com/emmansun/go-pkcs12)提供三个方法:
| 方法 | 适用 | 具体说明 |
| :--- | :--- | :--- |
| ```DecodeChain``` | 抽取出一个私钥、一个相应证书以及证书链 | 私钥和相应证书必须存在,否则报错 |
| ```Decode``` | 抽取出一个私钥、一个相应证书 | 私钥和相应证书必须存在,否则报错;并且**不能有证书链存在**。 |
| ```DecodeTrustStore``` | 抽取出证书链 | 只支持java的TrustStore, [Difference Between a Java Keystore and a Truststore](https://www.baeldung.com/java-keystore-truststore-difference) |
### 解码能处理的算法
#### 证书及私钥加密算法
这里主要是**PBES(Password-Based Encryption Scheme)**, 它主要涉及几方面:
1. 密码处理
2. 从密码派生出加密密钥
3. 具体对称加密算法
**PBES-PKCS12**
* pbeWithSHAAnd3-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3}
* pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 5}
* pbewithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 6}
不同于**PKCS#5 v1.5**中的**PBES1**,上述这些是**PKCS#12**的独有算法,特别是它的**KDF**和**密码处理**。
**PBES1**
PBES1属于老旧遗留算法目前版本未实现。
**PBES2**
由两部分组成,分别为**KDF**和加密算法。目前KDF只支持**KDF2**, KDF2中支持的**PRF**方法有:
* id-hmacWithSHA1
* id-hmacWithSHA256
* id-hmacWithSM3
具体可参考[PKCS #5: Password-Based Cryptography Specification Version 2.1](https://datatracker.ietf.org/doc/html/rfc8018)
加密算法有:
* AES-CBC-Pad密钥长度支持16/24/32字节
* SM4-CBC-Pad密钥长度支持16字节
#### 数据完整性保护(PBMAC)
这里只支持基于密码的完整性保护:**PKCS12-KDF + HMAC**。支持的HASH算法有
* SHA1
* SHA256
* SM3
**PBMAC**目前的实现还是基于**PKCS12-KDF**,将来看情况是否要实现**PBMAC1**,主要看**OpenSSL**的支持进度:
* [Support FIPS-compliant PKCS#12 files and create them by default in FIPS mode](https://github.com/openssl/openssl/issues/24546)
* [RFC 9579 implementation: add PBMAC1 with PBKDF2 to PKCS#12](https://github.com/openssl/openssl/pull/24577)
从**v0.4.1**开始支持**PBMAC1**。
## PKCS#12的生成
目前只支持下列几种,不支持自由定义:
* ```LegacyRC2```加密使用PKCS12特有算法对证书使用RC2加密对私钥使用3DES加密一致性保证使用HMAC-SHA1。
* ```LegacyDES```加密使用PKCS12特有算法对证书和私钥都是用3DES加密一致性保证使用HMAC-SHA1。
* ```Passwordless```,无加密、一致性保证模式。
* ```Modern2023```对应OpenSSL 3+ 默认加密使用AES-256-CBC with PBKDF2一致性保证使用HMAC-SHA256。
* ```ShangMi2024```,这个估计目前没什么互操作性。
目前的全局函数```Encode``` / ```EncodeTrustStore```使用**LegacyRC2**编码器。
```go
// LegacyRC2 encodes PKCS#12 files using weak algorithms that were
// traditionally used in PKCS#12 files, including those produced
// by OpenSSL before 3.0.0, go-pkcs12 before 0.3.0, and Java when
// keystore.pkcs12.legacy is defined. Specifically, certificates
// are encrypted using PBE with RC2, and keys are encrypted using PBE
// with 3DES, using keys derived with 2048 iterations of HMAC-SHA-1.
// MACs use HMAC-SHA-1 with keys derived with 1 iteration of HMAC-SHA-1.
//
// Due to the weak encryption, it is STRONGLY RECOMMENDED that you use [DefaultPassword]
// when encoding PKCS#12 files using this encoder, and protect the PKCS#12 files
// using other means.
//
// By default, OpenSSL 3 can't decode PKCS#12 files created using this encoder.
// For better compatibility, use [LegacyDES]. For better security, use
// [Modern2023].
var LegacyRC2 = &Encoder{
macAlgorithm: oidSHA1,
certAlgorithm: oidPBEWithSHAAnd40BitRC2CBC,
keyAlgorithm: oidPBEWithSHAAnd3KeyTripleDESCBC,
kdfPrf: nil,
encryptionScheme: nil,
macIterations: 1,
encryptionIterations: 2048,
saltLen: 8,
rand: rand.Reader,
}
// LegacyDES encodes PKCS#12 files using weak algorithms that are
// supported by a wide variety of software. Certificates and keys
// are encrypted using PBE with 3DES using keys derived with 2048
// iterations of HMAC-SHA-1. MACs use HMAC-SHA-1 with keys derived
// with 1 iteration of HMAC-SHA-1. These are the same parameters
// used by OpenSSL's -descert option. As of 2023, this encoder is
// likely to produce files that can be read by the most software.
//
// Due to the weak encryption, it is STRONGLY RECOMMENDED that you use [DefaultPassword]
// when encoding PKCS#12 files using this encoder, and protect the PKCS#12 files
// using other means. To create more secure PKCS#12 files, use [Modern2023].
var LegacyDES = &Encoder{
macAlgorithm: oidSHA1,
certAlgorithm: oidPBEWithSHAAnd3KeyTripleDESCBC,
keyAlgorithm: oidPBEWithSHAAnd3KeyTripleDESCBC,
kdfPrf: nil,
encryptionScheme: nil,
macIterations: 1,
encryptionIterations: 2048,
saltLen: 8,
rand: rand.Reader,
}
// Passwordless encodes PKCS#12 files without any encryption or MACs.
// A lot of software has trouble reading such files, so it's probably only
// useful for creating Java trust stores using [Encoder.EncodeTrustStore]
// or [Encoder.EncodeTrustStoreEntries].
//
// When using this encoder, you MUST specify an empty password.
var Passwordless = &Encoder{
macAlgorithm: nil,
certAlgorithm: nil,
keyAlgorithm: nil,
kdfPrf: nil,
encryptionScheme: nil,
rand: rand.Reader,
}
// Modern2023 encodes PKCS#12 files using algorithms that are considered modern
// as of 2023. Private keys and certificates are encrypted using PBES2 with
// PBKDF2-HMAC-SHA-256 and AES-256-CBC. The MAC algorithm is HMAC-SHA-2. These
// are the same algorithms used by OpenSSL 3 (by default), Java 20 (by default),
// and Windows Server 2019 (when "stronger" is used).
//
// Files produced with this encoder can be read by OpenSSL 1.1.1 and higher,
// Java 12 and higher, and Windows Server 2019 and higher.
//
// For passwords, it is RECOMMENDED that you do one of the following:
// 1) Use [DefaultPassword] and protect the file using other means, or
// 2) Use a high-entropy password, such as one generated with `openssl rand -hex 16`.
//
// You SHOULD NOT use a lower-entropy password with this encoder because the number of KDF
// iterations is only 2048 and doesn't provide meaningful protection against
// brute-forcing. You can increase the number of iterations using [Encoder.WithIterations],
// but as https://neilmadden.blog/2023/01/09/on-pbkdf2-iterations/ explains, this doesn't
// help as much as you think.
var Modern2023 = &Encoder{
macAlgorithm: oidSHA256,
certAlgorithm: oidPBES2,
keyAlgorithm: oidPBES2,
kdfPrf: oidHmacWithSHA256,
encryptionScheme: oidAES256CBC,
macIterations: 2048,
encryptionIterations: 2048,
saltLen: 16,
rand: rand.Reader,
}
// ShangMi2024 encodes PKCS#12 files using algorithms that are all ShangMi.
// Private keys and certificates are encrypted using PBES2 with PBKDF2-HMAC-SM3 and SM4-CBC.
// The MAC algorithm is PBMAC1-HMAC-SM3.
var ShangMi2024 = &Encoder{
macAlgorithm: oidPBMAC1,
certAlgorithm: oidPBES2,
keyAlgorithm: oidPBES2,
kdfPrf: oidHmacWithSM3,
encryptionScheme: oidSM4CBC,
messageAuthScheme: oidHmacWithSM3,
macIterations: 2048,
encryptionIterations: 2048,
saltLen: 16,
rand: rand.Reader,
}
```
## 解析加密的PKCS#8私钥
[go-pkcs12](https://github.com/emmansun/go-pkcs12) 也提供了```ParsePKCS8PrivateKey```方法,相比**pkcs8**的类似方法,这里特别支持**PBES-PKCS12**加密算法。
* PBE-SHA1-RC2-128
* PBE-SHA1-RC2-40
* PBE-SHA1-3DES

123
docs/pkcs7.md Normal file
View File

@ -0,0 +1,123 @@
# PKCS7应用指南
本项目实现 PKCS#7/加密消息语法的子集[RFC2315](https://www.rfc-editor.org/rfc/rfc2315.html)、[RFC5652](https://www.rfc-editor.org/rfc/rfc5652.html)以及相应国密支持《GB/T 35275-2017 信息安全技术 SM2密码算法加密签名消息语法规范》。这是 [mozilla-services/pkcs7](https://github.com/mozilla-services/pkcs7) 的一个分支,目前[mozilla-services/pkcs7](https://github.com/mozilla-services/pkcs7)已经是弃用状态,代码仓库也已经进入存档、只读状态。
## 支持的功能
### 数字信封数据Enveloped Data
数字信封数据,使用对称加密算法加密数据,使用非对称加密加密数据密钥。支持的对称加密算法(以及模式)有
* AES128-CBC
* AES192-CBC
* AES256-CBC
* AES128-GCM
* AES192-GCM
* AES256-GCM
* DES-CBC
* 3DES-CBC
* SM4-CBC
* SM4-GCM
支持的非对称加密算法为:
* RSAPKCS1v15目前尚不支持RSAOAEP
* SM2
#### 主要方法
是否国密是指OID也使用国密体系
| 是否国密 | 加密 | 解密(先调用```Parse``` |
| :--- | :--- | :--- |
| 否 | Encrypt | Decrypt |
| 否 | EncryptUsingPSK | DecryptUsingPSK |
| 是 | EncryptSM | Decrypt |
| 是 | EncryptCFCA | DecryptCFCA |
| 是 | EncryptSMUsingPSK | DecryptUsingPSK |
关于```EncryptSM / EncryptCFCA```的区别,请参考**CFCA互操作性指南**。
带PSKPre-shared key后缀的方法其对称加密密钥由调用者提供而非随机生成。
### 加密数据Encrypted Data
加密:对应本项目的```pkcs7.EncryptUsingPSK```和```pkcs7.EncryptSMUsingPSK```方法。
解密:对应本项目的```pkcs7.DecryptUsingPSK```方法(当然要先调用```pkcs7.Parse```)。
### 签名数据Signed Data
签名数据,使用证书对应的私钥进行签名,理论上支持多个签名者,但通常使用场景都是单签。和数字信封数据类似,也分国密和非国密。
#### 签名流程
1. 创建SignedData
是否国密是指OID也使用国密体系
| 是否国密 | 数据是否是哈希值 | 方法 | 默认签名算法 |
| :--- | :--- | :--- | :--- |
| 否 | 否 | ```NewSignedData``` | SHA1 |
| 否 | 是 | ```NewSignedDataWithDigest``` | SHA1 |
| 是 | 否 | ```NewSMSignedData``` | SM3 |
| 是 | 是 | ```NewSMSignedDataWithDigest``` | SM3 |
2. 可选步骤:调用```SetDigestAlgorithm```设置想要的签名算法,通常国密**不需要**修改。
3. 接着调用```AddSigner```或```AddSignerChain```方法,进行签名;可以通过```SignerInfoConfig.SkipCertificates```指定忽略证书项(最终签名数据中不包含证书项);
4. 如果进行Detach签名则调用```Detach```方法;
5. 最后调用```Finish```方法,序列化输出结果。
**注意**
1. 如果是直接对哈希值签名一定是Detach签名。
2. 国密签名如果要传入哈希值在有Attribute的情况下则哈希值只是标准的SM3哈希值否则必须是符合SM2签名标准的哈希值含SM2公钥信息
#### Detach签名
就是外部签名,**被签名数据**不包含在SignedData中也就是其ContentInfo.Content为空
In PKCS#7 SignedData, attached and detached formats are supported… In detached format, data that is signed is not embedded inside the SignedData package instead it is placed at some external location…
可以参考[RFC2315](https://www.rfc-editor.org/rfc/rfc2315.html)的第7章 注3
The optional omission of the content field makes it possible to construct "external signatures," for example, without modification to or replication of the content to which the signatures apply. In the case of external signatures, the content being signed would be omitted from the "inner" encapsulated ContentInfo value included in the signed-data content type.
这种外部签名要验签的话,需要先提供**被签名数据**。以下代码片段来自**sign_test.go**中的**testSign**方法:
```golang
p7, err := Parse(signed)
if err != nil {
t.Fatalf("test %s/%s/%s: cannot parse signed data: %s", sigalgroot, sigalginter, sigalgsigner, err)
}
if testDetach {
// Detached signature should not contain the content
// So we should not be able to find the content in the parsed data
// We should suppliment the content to the parsed data before verifying
p7.Content = content
}
if !bytes.Equal(content, p7.Content) {
t.Errorf("test %s/%s/%s: content was not found in the parsed data:\n\tExpected: %s\n\tActual: %s", sigalgroot, sigalginter, sigalgsigner, content, p7.Content)
}
if err := p7.VerifyWithChain(truststore); err != nil {
t.Errorf("test %s/%s/%s: cannot verify signed data: %s", sigalgroot, sigalginter, sigalgsigner, err)
}
```
#### 验证签名
而验证的话,流程如下:
1. 调用```Parse```方法;
2. 如果是Detach签名数据则手动设置原始数据参考```testSign```方法);
3. 如果签名数据中不包含证书项,则手动设置验签证书(参考```TestSkipCertificates```
4. 如果Content是原始数据调用```Verify```或```VerifyWithChain```方法如果Content是哈希值调用```VerifyAsDigest```或```VerifyAsDigestWithChain```方法。
#### 特殊方法
```DegenerateCertificate```退化成签名数据中只包含证书目前没有使用SM2 OID的方法如果需要可以请求添加。可以参考```TestDegenerateCertificate```和```TestParseSM2CertificateChain```。
### 签名及数字信封数据Signed and Enveloped Data
签名和数字信封数据使用场景较少有些实现用它来传输私钥譬如www.gmcert.org。具体请参考```sign_enveloped_test.go```。
The "signed and enveloped data" content type is a part of the Cryptographic Message Syntax (CMS), which is used in various Internet Standards. However, it's not recommended for use due to several reasons:
1. **Complexity**: The "signed and enveloped data" content type combines two operations - signing and enveloping (encryption). This increases the complexity of the implementation and can lead to potential security vulnerabilities if not handled correctly.
2. **Order of Operations**: The "signed and enveloped data" content type first signs the data and then encrypts it. This means that to verify the signature, the data must first be decrypted. This could potentially expose sensitive data to unauthorized parties before the signature is verified.
3. **Lack of Flexibility**: Combining signing and enveloping into a single operation reduces flexibility. It's often more useful to be able to perform these operations separately, as it allows for more varied use cases.
Instead of using the "signed and enveloped data" content type, it's generally recommended to use separate "signed data" and "enveloped data" content types. This allows the operations to be performed in the order that best suits the application's needs, and also simplifies the implementation.
#### 加密签名流程
1. 调用```NewSignedAndEnvelopedData```或者```NewSMSignedAndEnvelopedData```创建```SignedAndEnvelopedData```数据结构,此过程包含了数据加密过程;
2. 调用```AddSigner```或```AddSignerChain```方法,进行签名;
3. 调用```AddRecipient```方法用Recipient的公钥加密数据密钥
4. 最后调用```Finish```方法,序列化输出结果。
#### 解密验签流程
1. 调用```Parse```方法;
2. 调用```DecryptAndVerify```或者```DecryptAndVerifyOnlyOne```进行解密和验签。

368
docs/sm2.md Normal file
View File

@ -0,0 +1,368 @@
# SM2椭圆曲线公钥密码算法应用指南
## 参考标准
* 《GB/T 32918.1-2016 信息安全技术 SM2椭圆曲线公钥密码算法 第1部分总则》
* 《GB/T 32918.2-2016 信息安全技术 SM2椭圆曲线公钥密码算法 第2部分数字签名算法》
* 《GB/T 32918.3-2016 信息安全技术 SM2椭圆曲线公钥密码算法 第3部分密钥交换协议》
* 《GB/T 32918.4-2016 信息安全技术 SM2椭圆曲线公钥密码算法 第4部分公钥加密算法》
* 《GB/T 32918.5-2017 信息安全技术 SM2椭圆曲线公钥密码算法 第5部分参数定义》
* 《GB/T 35276-2017 信息安全技术 SM2密码算法使用规范》
* 《GB/T 33560-2017 信息安全技术 密码应用标识规范》
* 《GB/T 35275-2017 信息安全技术 SM2密码算法加密签名消息语法规范》(对应PKCS#7)
您可以从[国家标准全文公开系统](https://openstd.samr.gov.cn/)在线阅读这些标准。
## 概述
SM2既然是椭圆曲线公钥密码算法它就和NIST P系列椭圆曲线公钥密码算法类似特别是P-256。NIST P 系列椭圆曲线公钥密码算法主要用于数字签名和密钥交换NIST没有定义基于椭圆曲线的公钥加密算法标准[SEC 1: Elliptic Curve Cryptography](https://www.secg.org/sec1-v2.pdf)第五章定义了“Elliptic Curve Integrated Encryption Scheme (ECIES)”不过应用不广。SM2公钥加密算法与其相似只是MAC不同。感兴趣的同学可以进一步对比一下
| SM2 | SEC 1 |
| :--- | :--- |
| 数字签名算法 | ECDSA |
| 密钥交换协议 | ECMQV |
| 公钥加密算法 | ECIES |
**注**最新的阿里KMS支持ECIES难道客户有这个需求
ECIES_DH_SHA_1_XOR_HMAC遵循[SEC 1: Elliptic Curve Cryptography, Version 2.0](https://www.secg.org/sec1-v2.pdf)标准密钥协商算法采用ECDH密钥派生算法采用 KDF2 with SHA-1MAC算法采用HMAC-SHA-1对称加密算法采用XOR。
**业界对RSA非对称加密的安全性担忧与日俱增**
* [The Marvin Attack](https://people.redhat.com/~hkario/marvin/)
* [CVE-2023-45287 Detail](https://nvd.nist.gov/vuln/detail/CVE-2023-45287)
* [Vulnerability Report: GO-2023-2375](https://pkg.go.dev/vuln/GO-2023-2375)
* [Seriously, stop using RSA](https://blog.trailofbits.com/2019/07/08/fuck-rsa/)
## SM2公私钥对
SM2公私钥对的话要么是自己产生要么是别的系统产生后通过某种方式传输给您的。
### SM2公私钥对的生成
您可以通过调用```sm2.GenerateKey```方法产生SM2公私钥对SM2的私钥通过组合方式扩展了```ecdsa.PrivateKey```用于定义一些SM2特定的方法
```go
// PrivateKey represents an ECDSA SM2 private key.
// It implemented both crypto.Decrypter and crypto.Signer interfaces.
type PrivateKey struct {
ecdsa.PrivateKey
...
}
```
SM2的公钥类型沿用了```ecdsa.PublicKey```结构。注意Go从v1.20开始,```ecdsa.PublicKey```增加了```func (k *PublicKey) ECDH() (*ecdh.PublicKey, error)```方法这个方法对SM2的公钥不适用SM2公钥请使用```func PublicKeyToECDH(k *ecdsa.PublicKey) (*ecdh.PublicKey, error)```。
### SM2公钥的解析、构造
通常情况下公钥是通过PEM编码的文本传输的您可以通过两步获得公钥
* 获得PEM中的block
* 解析block中的公钥
```go
func getPublicKey(pemContent []byte) (any, error) {
block, _ := pem.Decode(pemContent)
if block == nil {
return nil, errors.New("Failed to parse PEM block")
}
return smx509.ParsePKIXPublicKey(block.Bytes)
}
```
由于```smx509.ParsePKIXPublicKey```返回any类型您需要通过```pub, ok := publicKey.(*ecdsa.PublicKey)```转型。
有些应用可能会直接存储公钥的曲线点X, Y 坐标值,这时候,您可以通过以下类似方法构造公钥(假设输入的是点的非压缩序列化字节数组):
```go
func ExampleNewPublicKey() {
keypoints, _ := hex.DecodeString("048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1")
pub, err := sm2.NewPublicKey(keypoints)
if err != nil {
log.Fatalf("fail to new public key %v", err)
}
fmt.Printf("%x\n", elliptic.Marshal(sm2.P256(), pub.X, pub.Y))
// Output: 048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1
}
```
当然您也可以使用ecdh包下的方法```ecdh.P256().NewPublicKey```来构造,目前只支持非压缩方式。
### SM2私钥的解析、构造
私钥的封装格式主要有以下几种,[相关讨论](https://github.com/emmansun/gmsm/issues/104)
* RFC 5915 / SEC1 - http://www.secg.org/sec1-v2.pdf
* PKCS#12
* PKCS#8
* PKCS#7《GB/T 35275-2017 信息安全技术 SM2密码算法加密签名消息语法规范》
* CFCA自定义封装
* 《GB/T 35276-2017 信息安全技术 SM2密码算法使用规范》
存在于智能密码钥匙中符合《GB/T 35291-2017 信息安全技术 智能密码钥匙应用接口规范》的,不在这里说明。)
所以当您拿到一个密钥文件您需要知道它的封装格式然后选用合适的方法。PEM编码的密钥文本通常第一行会有相关信息。如果您得到的是一个ASN.1编码那可能需要通过ASN.1结构和一些其中的OID来判断了。私钥信息是非常关键的信息通常密钥文件被加密保护。可能是标准落后于应用的原因目前这一块的互操作性可能差一点。
| 封装格式 | 解析方法 |
| :--- | :--- |
| RFC 5915 / SEC1 | ```smx509.ParseSM2PrivateKey``` |
| PKCS#12 | 使用 github.com/emmansun/go-pkcs12 解析 |
| PKCS#8 | ```smx509.ParsePKCS8PrivateKey```可以处理未加密的;```pkcs8.ParsePKCS8PrivateKeySM2```可以处理未加密的,也可以处理加密的 |
| PKCS#7 | Cryptographic Message Syntax, 可以参考github.com/emmansun/pkcs7/sign_enveloped_test.go中的```TestParseSignedEvnvelopedData```,测试数据来自 https://www.gmcert.org/ |
| CFCA自定义封装 | 顾名思义这个封装是CFCA特定的修改自PKCS#12,使用```cfca.ParseSM2```方法来解析 |
|《GB/T 35276-2017 信息安全技术 SM2密码算法使用规范》| 这个规范还比较新,使用```sm2.ParseEnvelopedPrivateKey```解析。典型的应用场景是CA机构返回CSRResponse, 里面包含签名证书、CA生成的SM2加密私钥以及相应的SM2加密证书其中SM2加密私钥就用该规范定义的方式加密封装。请参考《GM/T 0092-2020 基于SM2算法的证书申请语法规范》 |
有些系统可能会直接存储、得到私钥的字节数组,那么您可以使用如下方法来构造私钥:
```go
func ExampleNewPrivateKey() {
keyBytes, _ := hex.DecodeString("6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85")
priv, err := sm2.NewPrivateKey(keyBytes)
if err != nil {
log.Fatalf("fail to new private key %v", err)
}
fmt.Printf("%x\n", priv.D.Bytes())
// Output: 6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85
}
func ExampleNewPrivateKeyFromInt() {
key := big.NewInt(0x123456)
priv, err := sm2.NewPrivateKeyFromInt(key)
if err != nil {
log.Fatalf("fail to new private key %v", err)
}
fmt.Printf("%x\n", priv.D.Bytes())
// Output: 123456
}
```
当然你也可以使用ecdh包的方法```ecdh.P256().NewPrivateKey```来构造私钥您要确保输入的字节数组是256位32字节如果不是请先自行处理。
### 关于《GM/T 0091-2020 基于口令的密钥派生规范》
这个规范就是[RFC8018 PKCS#5](https://datatracker.ietf.org/doc/html/rfc8018) 国密定制版其中PBES/PBKDF/PBMAC使用了不同的OID但是这些OID似乎没有注册过。而且表A.1 中**id-hmacWithSM3**的OID为没有注册过的**1.2.156.10197.1.401.3.1**,和我们常用的**1.2.156.10197.1.401.2**不一致也与该文档本身附录C不一致。不知道哪个产品遵从了这个行业规范。
| 对象标识符OID | 对象标识符定义 |
| :--- | :--- |
| 1.2.156.10197.6.1.4.1.5 | 基于口令的密钥派生规范 |
| 1.2.156.10197.6.1.4.1.5.1 | 基于口令的密钥派生函数 PBKDF (其实就是PBKDF2) |
| 1.2.156.10197.6.1.4.1.5.2 | 基于口令的加密方案PBES (其实就是PBES2) |
| 1.2.156.10197.6.1.4.1.5.3 | 基于口令的消息鉴别码PBMAC |
规范中让人困惑的地方:
1. 附录 **A.2 伪随机函数** 引入了这个新的**id-hmacWithSM3**的OID**1.2.156.10197.1.401.3.1**
2. 附录 **A.4 基础消息鉴别方案**给出的实例片段中的OID为**1.2.156.10197.1.401**,让人怀疑这个实例抄的是**PKCS12-MAC**,而不是**PBMAC1**。
3. 附录 **B.2 PBES结构****PBES-Encs**竟然给出了**pbeWithSM3AndSM4-CBC OJBECTIDENTIFIER ::= {1.2.156.10197.6.1.4.1.12.1.1}**,难不成又要抄**PBES1**?
4. 附录 **C. ASN.1 结构定义****id-hmacWithSM3**的OID又是**1.2.156.10197.1.401.2**。
## 数字签名算法
您可以直接使用sm2私钥的签名方法```Sign```
```go
// This is a reference method to force SM2 standard with SDK [crypto.Signer].
func ExamplePrivateKey_Sign_forceSM2() {
toSign := []byte("ShangMi SM2 Sign Standard")
// real private key should be from secret storage
privKey, _ := hex.DecodeString("6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85")
testkey, err := sm2.NewPrivateKey(privKey)
if err != nil {
log.Fatalf("fail to new private key %v", err)
}
// force SM2 sign standard and use default UID
sig, err := testkey.Sign(rand.Reader, toSign, sm2.DefaultSM2SignerOpts)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from sign: %s\n", err)
return
}
// Since sign is a randomized function, signature will be
// different each time.
fmt.Printf("%x\n", sig)
}
```
我们通过```SignerOpts```参数来指示```toSign```已经是hash值还是需要进行处理的原始信息。通常情况下```toSign```传入原始信息、```SignerOpts```传入```sm2.DefaultSM2SignerOpts```。如果将来标准支持自定义的uid那么您可以通过调用```sm2.NewSM2SignerOption```来构造一个自定义的```SignerOpts```。
当然您也可以通过调用SM2私钥的```SignWithSM2```方法,区别在于,```Sign```方法是```crypto.Singer```接口中定义的方法,而```SignWithSM2```方法是```sm2.Signer```接口中定义的方法。
您可以使用```sm2.VerifyASN1WithSM2```来校验SM2签名
```go
func ExampleVerifyASN1WithSM2() {
// real public key should be from cert or public key pem file
keypoints, _ := hex.DecodeString("048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1")
testkey, err := sm2.NewPublicKey(keypoints)
if err != nil {
log.Fatalf("fail to new public key %v", err)
}
toSign := []byte("ShangMi SM2 Sign Standard")
signature, _ := hex.DecodeString("304402205b3a799bd94c9063120d7286769220af6b0fa127009af3e873c0e8742edc5f890220097968a4c8b040fd548d1456b33f470cabd8456bfea53e8a828f92f6d4bdcd77")
ok := sm2.VerifyASN1WithSM2(testkey, nil, toSign, signature)
fmt.Printf("%v\n", ok)
// Output: true
}
```
### 如何处理不用Z的签名、验签
所谓**Z**就是用户可识别标识符和用户公钥、SM2椭圆曲线参数的杂凑值。其它签名算法如ECDSA是没有这个**Z**的这也是SM2签名算法难以融入以ECDSA签名算法为主的体系的主因。
#### 签名
也是使用sm2私钥的`Sign`方法,只是```SignerOpts```传入`nil`或者其它非`SM2SignerOption`即可,那么,你自己负责预先计算杂凑值,当然如何计算杂凑值,由你自己说了算了。
#### 验签
调用`sm2.VerifyASN1`方法,同样,你自己负责预先计算杂凑值,确保杂凑算法和签名时使用的杂凑算法保持一致。
### 如何对大文件签名、验签?
解决方案就是对杂凑值进行签名、验签。`sm2.CalculateSM2Hash`并不适合对大文件进行杂凑计算,请使用专门的`hash.Hash`接口实现。
## 密钥交换协议
这里有两个实现一个是传统实现位于sm2包中另外一个参考最新go语言的实现在ecdh包中。在这里不详细介绍使用方法一般只有tls/tlcp才会用到普通应用通常不会涉及这一块感兴趣的话可以参考github.com/Trisia/gotlcp中的应用。
## 公钥加密算法
请牢记,非对称加密算法通常不用于加密大量数据,而是用来加密对称加密密钥,我们在**tlcp**以及**信封加密**机制中能找到这种用法。
SM2公钥加密算法支持的密文编码格式有两种
* 简单串接方式: C1C3C2曾经老的标准为 C1C2C3
* ASN.1格式
SM2公钥加密示例
```go
func ExampleEncryptASN1() {
// real public key should be from cert or public key pem file
keypoints, _ := hex.DecodeString("048356e642a40ebd18d29ba3532fbd9f3bbee8f027c3f6f39a5ba2f870369f9988981f5efe55d1c5cdf6c0ef2b070847a14f7fdf4272a8df09c442f3058af94ba1")
testkey, err := sm2.NewPublicKey(keypoints)
if err != nil {
log.Fatalf("fail to new public key %v", err)
}
secretMessage := []byte("send reinforcements, we're going to advance")
// crypto/rand.Reader is a good source of entropy for randomizing the
// encryption function.
rng := rand.Reader
ciphertext, err := sm2.EncryptASN1(rng, testkey, secretMessage)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
return
}
// Since encryption is a randomized function, ciphertext will be
// different each time.
fmt.Printf("Ciphertext: %x\n", ciphertext)
}
```
如果您需要普通拼接编码输出,您可以调用```sm2.Encrypt```方法,其中```EncrypterOpts```类型参数可以传入nil表示默认C1C3C2。
sm2包也提供了辅助方法用于密文输出编码格式转换您可以通过```sm2.ASN1Ciphertext2Plain```方法把ASN.1密文转换为简单拼接输出;反过来,您也可以通过```sm2.PlainCiphertext2ASN1```将简单拼接密文输出转换为ASN.1密文。你还可以通过```sm2.AdjustCiphertextSplicingOrder```方法来改变串接顺序。
SM2公钥加密算法解密示例
```go
func ExamplePrivateKey_Decrypt() {
ciphertext, _ := hex.DecodeString("308194022100bd31001ce8d39a4a0119ff96d71334cd12d8b75bbc780f5bfc6e1efab535e85a02201839c075ff8bf761dcbe185c9750816410517001d6a130f6ab97fb23337cce150420ea82bd58d6a5394eb468a769ab48b6a26870ca075377eb06663780c920ea5ee0042be22abcf48e56ae9d29ac770d9de0d6b7094a874a2f8d26c26e0b1daaf4ff50a484b88163d04785b04585bb")
// real private key should be from secret storage
privKey, _ := hex.DecodeString("6c5a0a0b2eed3cbec3e4f1252bfe0e28c504a1c6bf1999eebb0af9ef0f8e6c85")
testkey, err := sm2.NewPrivateKey(privKey)
if err != nil {
log.Fatalf("fail to new private key %v", err)
}
plaintext, err := testkey.Decrypt(nil, ciphertext, nil)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err)
return
}
fmt.Printf("Plaintext: %s\n", string(plaintext))
// Output: Plaintext: send reinforcements, we're going to advance
}
```
这个SM2私钥的解密方法```Decrypt```,通常情况下,对```crypto.DecrypterOpts```类型参数您只需传入nil系统会自己检测输入密文是ASN.1还是普通拼接但是如果密文是老旧的C1||C2||C3拼接请传入相应的```crypto.DecrypterOpts```类型参数,或者您可以先通过上面介绍的辅助函数转换一下。
具体API文档请参考[API Document](https://godoc.org/github.com/emmansun/gmsm)
### 关于C1C2C3 和 C1C3C2
目前有据可查的是国家密码管理局2010版SM2标准还是用C1C2C3格式到了2012年标准就改用了C1C3C2并延续至今。
其实C1C2C3是符合《SEC 1: Elliptic Curve Cryptography》May 21, 2009 Version 2.0Elliptic Curve Integrated Encryption Scheme 5.1.3中的密文输出描述9. Output C = ($\overline{\text{R}}$, EM, D). Optionally, the ciphertext maybe output as C = $\overline{\text{R}}$ || EM || D. 这里 $\overline{\text{R}}$ 相对于C1, EM相对于C2, D相对于C3。
### 关于点到字节串的转换
我没有找到到哪个文档写有固定64字节转换的。从国家密码管理局2010年版的《SM2椭圆曲线公钥密码算法》到2012年的GM/T 0003-2012 SM2椭圆曲线公钥密码算法再到GB/T 32918-2016 信息安全技术 SM2椭圆曲线公钥密码算法都在第一部分第四章的“点到字节串的转换”有详细说明。这也符合《SEC 1: Elliptic Curve Cryptography》May 21, 2009 Version 2.0中2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion的描述。
#### 来自AI的问答
**问: 为什么一些crypto实现中椭圆曲线点转换为八位字节串时没有使用格式指示符**
**答:** 在椭圆曲线密码学ECC椭圆曲线点转换为八位字节串的方法有多种通常可以是压缩形式或未压缩形式。格式指示符也称为前缀用于表示该点是以压缩形式还是未压缩形式表示。
然而,一些实现可能会出于几个原因选择省略格式指示符:
1. **简洁性**:省略格式指示符可以简化实现过程,因为不需要处理不同形式的点表示。
2. **预设知识**:如果事先知道所有点都将处于某种特定形式(例如,所有点总是未压缩的),则可能会认为格式指示符是不必要的。
3. **兼容性**:并非所有系统或库都支持两种形式的点表示。为了确保最大兼容性,实现可能会选择始终使用一种形式,从而省略格式指示符。
4. **安全性**:在某些情况下,为了防止依赖于点形式的某些类型的攻击,可能会省略格式指示符。
请注意,这些是通用原因,具体原因可能会根据确切的上下文以及使用的特定密码协议或系统而有所不同。
**问:这不会引起互操作性问题吗?**
**答:** 是的,你说得对。在将椭圆曲线点转换为八位字节串时省略格式指示符,确实可能导致互操作性问题。
当系统需要互操作时,它们必须就数据交换的通用格式达成一致。如果一个系统在编码椭圆曲线点时没有使用格式指示符,而另一个系统期望格式指示符存在,它们将无法正确解释彼此的数据。
这就是为什么像SEC高效密码学标准这样的标准会指定使用格式指示符。例如SEC 1标准指定未压缩点的格式指示符应为0x04压缩点的格式指示符应为0x02或0x03。
因此,虽然在封闭系统中省略格式指示符可能会简化实现或提供其他好处,但它可能会阻碍与其他系统的互操作性。在编码和解码密码数据时,通常最好遵循已建立的标准,以确保最大的兼容性。
### 性能
从**v0.27.0**开始对大数据量的加解密做了优化处理尤其是KDF并行计算。详情请参考[SM2加解密性能](https://github.com/emmansun/gmsm/wiki/SM2%E5%8A%A0%E8%A7%A3%E5%AF%86%E6%80%A7%E8%83%BD)。
## 与KMS集成
国内云服务商的KMS服务大都提供SM2密钥我们一般调用其API进行签名和解密而验签和加密操作一般在本地用公钥即可完成。不过需要注意的是KMS提供的签名通常需要您在本地进行hash操作而sm2签名的hash又比较特殊下面示例供参考自版本**v0.24.0**开始,您可以直接使用函数```sm2.CalculateSM2Hash```
```go
func calculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
if len(uid) == 0 {
uid = defaultUID
}
za, err := sm2.CalculateZA(pub, uid)
if err != nil {
return nil, err
}
md := sm3.New()
md.Write(za)
md.Write(data)
return md.Sum(nil), nil
}
```
公钥加密就没啥特殊只要确保输出密文的编码格式和KMS一致即可。
## 基于密码硬件定制SM2私钥
密码硬件SDF/SKF中的用户密钥私钥通常是无法导出的但都提供了签名、解密APIs供调用为了和本软件库集成需要实现以下接口
1. `crypto.Signer`,这个接口的实现通常把传入的数据作为哈希值。
2. `crypto.Decrypter`,这个接口用于解密操作。
通常需要实现四个方法:
1. `Public() crypto.PublicKey`
2. `Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)`
3. `Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error)`
第一个返回公钥的方法是必须要实现的后面的方法取决于这个KEY的用途。
**注意**
1. `Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)`方法通常用于对哈希值作签名,最好遵从以下实现逻辑:检查`opts`是否是`*sm2.SM2SignerOption`类型,如果是,则把传入的`digest`作为原始数据进行处理,具体实现可以参考`sm2.SignASN1`函数。当然,在大多数情况下,直接将数据视为原始数据是可行的。实施者可以根据具体的应用场景灵活处理。
2. 如果密码硬件有自己的随机数源,可以忽略传入的`rand`
3. 很多设备签名函数通常只接收哈希值,需要调用```sm2.CalculateSM2Hash```或者**SDF**提供的哈希函数计算哈希值。
SDF API请参考《GB/T 36322-2018 密码设备应用接口规范》
## SM2扩展应用
SM2的一些扩展应用譬如从签名中恢复公钥、半同态加密、环签名等大多尚处于POC状态也无相关标准。其它扩展应用但凡椭圆曲线公钥密码算法能用到的场合包括但不限于
* [确定性签名](https://datatracker.ietf.org/doc/html/rfc6979)
* [可验证随机函数ECVRF](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-04)
* 盲签名
* 群签名
* 门限签名
* [Pederson承诺](https://crypto.stackexchange.com/questions/64437/what-is-a-pedersen-commitment)
### 从签名中恢复公钥
ECDSA 签名由两个数字整数组成r 和 s。以太坊还引入了额外的变量 v恢复标识符。签名可以表示成 {r, s, v}。SM2 签名也由两个数字整数组成r 和 s。签名算法中都只取随机点的X坐标并对N取模所以只有签名r和s的情况下可以恢复出多个公钥。
```go
// RecoverPublicKeysFromSM2Signature recovers two or four SM2 public keys from a given signature and hash.
// It takes the hash and signature as input and returns the recovered public keys as []*ecdsa.PublicKey.
// If the signature or hash is invalid, it returns an error.
// The function follows the SM2 algorithm to recover the public keys.
func RecoverPublicKeysFromSM2Signature(hash, sig []byte) ([]*ecdsa.PublicKey, error)
```
返回的结果:
* 公钥0 - Rx = (r - e) mod N; Ry是偶数compressFlag = 2
* 公钥1 - Rx = (r - e) mod N; Ry是奇数compressFlag = 3
* 公钥2 - Rx = ((r - e) mod N) + N; Ry是偶数compressFlag = 2
* 公钥3 - Rx = ((r - e) mod N) + N; Ry是奇数compressFlag = 3
Rx, Ry代表随机点R的X,Y坐标值。绝大多数情况下只会返回两个公钥后两者只有当(r - e) mod N的值小于P-1-N时才可能。
### 半同态加解密
EC-ElGamal with SM2的半同态加密Partially Homomorphic Encryption, PHE, 支持uint32 或者 int32类型。[Partially Homomorphic Encryption, EC-ElGamal with SM2](https://github.com/emmansun/sm2elgamal).
### 环签名
[Ring Signature Schemes Based on SM2 Digital Signature Algorithm](https://github.com/emmansun/sm2rsign).

46
docs/sm3.md Normal file
View File

@ -0,0 +1,46 @@
# SM3密码杂凑算法
## 参考标准
* 《GB/T 32905-2016 信息安全技术 SM3密码杂凑算法》
您可以从[国家标准全文公开系统](https://openstd.samr.gov.cn/)在线阅读此标准。
## 概述
SM3密码杂凑算法或者叫SM3哈希算法它是一个输出结果为256位32字节的哈希算法。在本软件库中SM3的实现方法签名与Go语言中的哈希算法特别是SHA256保持一致所以用法也是一样的。具体API文档包括Example请参考[API Document](https://godoc.org/github.com/emmansun/gmsm)。
## 常用用法示例
```go
// 直接使用sm3.Sum方法
func ExampleSum() {
sum := sm3.Sum([]byte("hello world\n"))
fmt.Printf("%x", sum)
// Output: 4cc2036b86431b5d2685a04d289dfe140a36baa854b01cb39fcd6009638e4e7a
}
// 先创建sm3 hash实例再进行hash计算
func ExampleNew() {
h := sm3.New()
h.Write([]byte("hello world\n"))
fmt.Printf("%x", h.Sum(nil))
// Output: 4cc2036b86431b5d2685a04d289dfe140a36baa854b01cb39fcd6009638e4e7a
}
// 计算文件内容hash
func ExampleNew_file() {
f, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
h := sm3.New()
if _, err := io.Copy(h, f); err != nil {
log.Fatal(err)
}
fmt.Printf("%x", h.Sum(nil))
}
```
## 性能
请参考[SM3密码杂凑算法性能优化](https://github.com/emmansun/gmsm/wiki/SM3%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96)。

268
docs/sm4.md Normal file
View File

@ -0,0 +1,268 @@
# SM4分组密码算法应用指南
## 参考标准
* 《GB/T 32907-2016 信息安全技术 SM4分组密码算法》
* 《GB/T 17964-2021 信息安全技术 分组密码算法的工作模式》
您可以从[国家标准全文公开系统](https://openstd.samr.gov.cn/)在线阅读这些标准。
## 概述
SM4分组密码算法其地位类似NIST中的AES分组密码算法密钥长度128位16字节分组大小也是128位16字节。在本软件库中SM4的实现与Go语言中的AES实现一致也实现了```cipher.Block```接口所以所有Go语言中实现的工作模式CBC/GCM/CFB/OFB/CTR都能与SM4组合使用。
## [工作模式](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation)
Go语言实现的工作模式主要有三类
* 基于分组的工作模式 ```cipher.BlockMode```譬如CBC。
* 带有关联数据的认证加密工作模式```cipher.AEAD```譬如GCM。
* 流加密工作模式```cipher.Stream```譬如CTR、CFB、OFB。
在实际加解密操作中,我们一般不会直接使用```cipher.Block```必须结合分组密码算法的工作模式使用。除了Go语言自带的工作模式CBC/GCM/CFB/OFB/CTR本软件库也实现了下列工作模式
* ECB - 电码本模式
* BC - 分组链接模式
* HCTR - 带泛杂凑函数的计数器模式
* XTS - 带密文挪用的XEX可调分组密码模式
* OFBNLF - 带非线性函数的输出反馈模式
* CCM - 分组密码链接-消息认证码组合模式
其中ECB/BC/HCTR/XTS/OFBNLF是《GB/T 17964-2021 信息安全技术 分组密码算法的工作模式》列出的工作模式。BC/OFBNLF模式是商密中的遗留工作模式**不建议**在新的应用中使用。XTS/HCTR模式适用于对磁盘加密其中HCTR模式是《GB/T 17964-2021 信息安全技术 分组密码算法的工作模式》最新引入的HCTR模式最近业界研究比较多也指出了原论文中的BugsOn modern processors HCTR [WFW05](https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.470.5288) is one of the most efficient constructions for building a tweakable super-pseudorandom permutation. However, a bug in the specification and another in Chakraborty and Nandis security proof [CN08](https://www.iacr.org/cryptodb/archive/2008/FSE/paper/15611.pdf) invalidate the claimed security bound.
不知道这个不足是否会影响到这个工作模式的采用。很奇怪《GB/T 17964-2021 信息安全技术 分组密码算法的工作模式》为何没有纳入GCM工作模式难道是版权问题
本软件库引入CCM模式只是为了有些标准还用到该模式。ECB模式也不建议单独使用。
目前本软件库的SM4针对ECB/CBC/GCM/XTS工作模式进行了绑定组合性能优化暂时没有计划使用汇编优化HCTR模式HCTR模式可以采用和GCM类似的方法进行汇编优化
### 使用建议
常用的对称加解密应用场合推荐优先使用GCM模式其次CBC模式一些安全扫描工具也会把CBC工作模式列为安全性不高的工作模式。我能想到的GCM模式的缺点是加解密的相关方不支持GCM模式或者实现性能不好。
#### 关于ECB模式
1. 请使用本软件库提供的`NewECBEncrypter/NewECBDecrypter`方法,否则大概率不会得到性能优化。
2. 基于安全考虑,最好不要使用该模式。
## 填充padding
有些分组密码算法的工作模式(譬如实现了```cipher.BlockMode```接口的模式的输入要求是其长度必须是分组大小的整数倍。《GB/T 17964-2021 信息安全技术 分组密码算法的工作模式》附录C中列出了以下几种填充模式
* 填充方式 1对应本软件库的```padding.NewPKCS7Padding```
* 填充方式 2对应本软件库的```padding.NewISO9797M2Padding```
* 填充方式 3目前没有实现它对应ISO/IEC_9797-1 padding method 3
本软件库也实现了ANSI X9.23标准中定义的填充方式```padding.NewANSIX923Padding```**用的最广的还是填充方式 1PKCS7填充**。
您如果使用实现了```cipher.BlockMode```接口的分组加密工作模式那您也必须与相关方协调好填充模式。JAVA库的对称加密算法字符串名就包含了所有信息譬如**AES/CBC/PKCS7Padding**。
## 密文及其相关参数的传输和存储
如果是自描述的那肯定有相关标准定义相关ASN.1结构并且给分组密码算法、工作模式、填充方式都赋予一个OID。或者如hashicorp vault一个对称密钥确定了分组密码算法、工作模式、填充方式最终输出密文是密钥ID和原始密文的组合。
如果是内部服务之间,可能是在应用/服务级别自定义所使用分组密码算法、工作模式、填充方式的标识作为应用的METADATA也就是加密用的METADATA和密文分离。
也可能是隐式使用一致的分组密码算法、工作模式、填充方式,也就是代码知道,还有文档知道?
具体使用哪种方式,取决于应用场景。
另外一个就是必须和密文一起存储/传输的参数譬如如果使用CBC工作模式那IV怎么办如果是GCM模式那Nonce、Nonce长度、Tag长度怎么办这通常也有两种方案
* 使用预定义的ASN.1结构
* 和密文简单拼接譬如CBC工作模式前面16字节IV后面ciphertextGCM模式使用默认Tag长度和Nonce长度前面12字节Nonce后面ciphertext。
至于要将二进制转为文本传输、存储编个码就行标准base64 / URL base64 / HEX事先协调、定义好就可以了。这里顺便推荐一下[性能更好的BASE64实现](https://github.com/emmansun/base64)。
## API文档及示例
这里只列出GCM/CBC的例子其余请参考[API Document](https://godoc.org/github.com/emmansun/gmsm)。
### GCM示例
```go
func Example_encryptGCM() {
// Load your secret key from a safe place and reuse it across multiple
// Seal/Open calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("exampleplaintext")
block, err := sm4.NewCipher(key)
if err != nil {
panic(err.Error())
}
// Never use more than 2^32 random nonces with a given key because of the risk of a repeat.
nonce := make([]byte, 12)
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
panic(err.Error())
}
sm4gcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
// You can encode the nonce and ciphertext with your own scheme
ciphertext := sm4gcm.Seal(nil, nonce, plaintext, nil)
fmt.Printf("%x %x\n", nonce, ciphertext)
}
func Example_decryptGCM() {
// Load your secret key from a safe place and reuse it across multiple
// Seal/Open calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
// You can decode the nonce and ciphertext with your encoding scheme
ciphertext, _ := hex.DecodeString("b7fdece1c6b3dce9cc386e8bc93df0ce496df789166229f14b973b694a4a23c3")
nonce, _ := hex.DecodeString("07d168e0517656ab7131f495")
block, err := sm4.NewCipher(key)
if err != nil {
panic(err.Error())
}
sm4gcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
plaintext, err := sm4gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
panic(err.Error())
}
fmt.Printf("%s\n", plaintext)
// Output: exampleplaintext
}
```
### CBC示例
```go
func Example_encryptCBC() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("sm4 exampleplaintext")
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
// CBC mode works on blocks so plaintexts may need to be padded to the
// next whole block. For an example of such padding, see
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2.
pkcs7 := padding.NewPKCS7Padding(sm4.BlockSize)
paddedPlainText := pkcs7.Pad(plaintext)
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, sm4.BlockSize+len(paddedPlainText))
iv := ciphertext[:sm4.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[sm4.BlockSize:], paddedPlainText)
fmt.Printf("%x\n", ciphertext)
}
func Example_decryptCBC() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
ciphertext, _ := hex.DecodeString("4d5a1486bfda1b34447afd5bb852e77a867cc6b726a8a0e0ef9b2c21fffc3a30b42acf504628f65cb3fba339101c98ff")
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
if len(ciphertext) < sm4.BlockSize {
panic("ciphertext too short")
}
iv := ciphertext[:sm4.BlockSize]
ciphertext = ciphertext[sm4.BlockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
// CryptBlocks can work in-place if the two arguments are the same.
mode.CryptBlocks(ciphertext, ciphertext)
// Unpad plaintext
pkcs7 := padding.NewPKCS7Padding(sm4.BlockSize)
ciphertext, err = pkcs7.Unpad(ciphertext)
if err != nil {
panic(err)
}
fmt.Printf("%s\n", ciphertext)
// Output: sm4 exampleplaintext
}
```
需要注意一下,```cipher.AEAD```对```dst```参数的要求:
```cipher.AEAD```是**追加**结果,所以如果要重用切片,要注意一下。而且```Seal```的结果要比plaintext长加上tag所以只有```cap(plaintext)>=len(plaintext)+tagSize```时才会重用,否则还是会新建一个切片。
```go
// AEAD is a cipher mode providing authenticated encryption with associated
// data. For a description of the methodology, see
// https://en.wikipedia.org/wiki/Authenticated_encryption.
type AEAD interface {
// NonceSize returns the size of the nonce that must be passed to Seal
// and Open.
NonceSize() int
// Overhead returns the maximum difference between the lengths of a
// plaintext and its ciphertext.
Overhead() int
// Seal encrypts and authenticates plaintext, authenticates the
// additional data and appends the result to dst, returning the updated
// slice. The nonce must be NonceSize() bytes long and unique for all
// time, for a given key.
//
// To reuse plaintext's storage for the encrypted output, use plaintext[:0]
// as dst. Otherwise, the remaining capacity of dst must not overlap plaintext.
Seal(dst, nonce, plaintext, additionalData []byte) []byte
// Open decrypts and authenticates ciphertext, authenticates the
// additional data and, if successful, appends the resulting plaintext
// to dst, returning the updated slice. The nonce must be NonceSize()
// bytes long and both it and the additional data must match the
// value passed to Seal.
//
// To reuse ciphertext's storage for the decrypted output, use ciphertext[:0]
// as dst. Otherwise, the remaining capacity of dst must not overlap plaintext.
//
// Even if the function fails, the contents of dst, up to its capacity,
// may be overwritten.
Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error)
}
```
而```cipher.BlockMode```和```cipher.Stream```的话,则是直接覆盖。
## 性能
SM4分组密码算法的软件高效实现不算CPU指令支持的话已知有如下几种方法
* S盒和L转换预计算本软件库纯Go语言实现采用该方法
* SIMD并行处理并行查表
* SIMD并行处理借助CPU的AES指令本软件库采用该方法
* SIMD并行处理借助CPU的GFNI指令部分新AMD64 CPU架构支持该指令本软件库尚未实现[SM4 with GFNI](https://github.com/emmansun/gmsm/wiki/SM4-with-GFNI)
* SIMD并行处理位切片(bitslicing)[参考实现](https://github.com/emmansun/sm4bs)
当然这些与有CPU指令支持的AES算法相比性能差距依然偏大要是工作模式不支持并行差距就更巨大了。
### 混合方式
从**v0.25.0**开始AMD64/ARM64 支持AES-NI的CPU架构下**默认会使用混合方式**,即```cipher.Block```的方法会用纯Go语言实现而对于可以并行的加解密模式则还是会尽量采用AES-NI和SIMD并行处理。您可以通过环境变量```FORCE_SM4BLOCK_AESNI=1```来强制都使用AES-NI实现和v0.25.0之前版本的行为一样)。请参考[SM4: 单block的性能问题](https://github.com/emmansun/gmsm/discussions/172)。
**注意**目前的纯Golang SM4实现查表实现是以可变时间运行的
## 与KMS集成
可能您会说如果我在KMS中创建了一个SM4对称密钥就不需要本地加解密了这话很对不过有种场景会用到
* 在KMS中只创建非对称密钥KEK
* 对称加解密在本地进行;
* 对称加密密钥,或者称为数据密钥(DEK/CEK)可以在本地通过安全伪随机数函数生成也可以通过KMS的Data Key API生成如果有这类API的话用Data Key API的话会有DEK/CEK明文传输问题毕竟KMS需要把DEK/CEK的密文/明文同时返回。
这种加密方案有什么优点呢?
* KMS API通常都会限流譬如200次/秒通过把对称加解密放在本地进行可以有效减少KMS交互。
* 减少网络带宽占用。
* 避免明文数据的网络传输。
当然前提是用于本地对称加解密的SM4分组密码算法和选用的工作模式性能可以满足需求。

329
docs/sm9.md Normal file
View File

@ -0,0 +1,329 @@
# SM9标识密码算法应用指南
## 参考标准
* 《GB/T 38635.1-2020 信息安全技术 SM9标识密码算法 第1部分总则》
* 《GB/T 38635.2-2020 信息安全技术 SM9标识密码算法 第2部分算法》
* 《GB/T 41389-2022 信息安全技术 SM9密码算法使用规范》
* 《GM/T 0086-2020 基于SM9标识密码算法的密钥管理系统技术规范》
您可以从[国家标准全文公开系统](https://openstd.samr.gov.cn/)在线阅读这些标准。
## 概述
SM9算法是一种基于双线性对的标识密码算法简称“IBC”由数字签名算法、标识加密算法、密钥协商协议三部分组成相比于传统密码体系SM9密码系统号称的**最大的优势就是无需证书、易于使用、易于管理、总体拥有成本低**,但这显然过于理想化:
* **KGC**中心的标准化与权威性。标志密码算法依然需要主密钥需要中心化的KGC私有系统可能自己搞个简单点的服务就行但作为公共、公开服务系统没有标准化与权威性是不行的。
* 用户私钥依然有被盗、遗失的风险,所以依然有用户标识作废、重新启用等需求。这也意味着客户端依然需要访问**KGC**的公开参数服务,查询用户标识状态。
* **《GM/T 0086-2020 基于SM9标识密码算法的密钥管理系统技术规范》** 定义了相关规范但不知道有没有建成相关系统。且这和传统的公钥体系PKI相比有何优势
同时SM9标识密码算法还有以下问题
* 基于双线性对的标识密码算法的实现复杂度和性能问题本软件库的SM9实现其签名、验签性能不到SM2的十分之一
* SM9标识密码算法选择的bn256曲线安全问题[128位安全性挑战](https://moderncrypto.org/mail-archive/curves/2016/000740.html)
上述只是简单的探讨没有贬低SM9标识密码算法的意思。
## 主公私钥对
SM9标识密码算法用于签名和加密的主公私钥对是分开的需要各自独立生成
* ```sm9.GenerateSignMasterKey```用于生成签名主密钥对。
* ```sm9.GenerateEncryptMasterKey```用于生成加密主密钥对。
其中签名主公钥是G2上的点加密主公钥是G1上的点而签名、加密主私钥都是一个随机大整数。
主公私钥的ASN.1数据格式定义请参考《GB/T 41389-2022 信息安全技术 SM9密码算法使用规范》和椭圆曲线的公私钥ASN.1数据格式类似。本软件实现了相应的Marshal/Unmarshal方法。
## 用户私钥
用户的签名私钥由签名主私钥、用户标识生成:```(master *SignMasterPrivateKey) GenerateUserKey(uid []byte, hid byte) (*SignPrivateKey, error)```它是G1上的点。
用户的加密私钥由加密主私钥、用户标识生成:```func (master *EncryptMasterPrivateKey) GenerateUserKey(uid []byte, hid byte) (*EncryptPrivateKey, error)```它是G2上的点。
《GB/T 41389-2022 信息安全技术 SM9密码算法使用规范》中 hid 定义如下:
* hid = 1签名
* hid = 3加密
本软件实现没有硬编码**hid**的值。
用户签名、加密私钥的ASN.1数据格式定义请参考《GB/T 41389-2022 信息安全技术 SM9密码算法使用规范》和椭圆曲线点的ASN.1数据格式类似。本软件实现了相应的Marshal/Unmarshal方法。
目前```smx509```中实现的```MarshalPKCS8PrivateKey/ParsePKCS8PrivateKey```没有相关标准,只是为了和[gmssl](https://github.com/guanzhi/GmSSL)互操作验证,请参考[sm9:【feature】是否考虑支持 pem 格式的公私钥输出](https://github.com/emmansun/gmsm/issues/86)。
```go
func TestMarshalPKCS8SM9SignPrivateKey(t *testing.T) {
masterKey, err := sm9.GenerateSignMasterKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
privateKey, err := masterKey.GenerateUserKey([]byte("emmansun"), 0x01)
if err != nil {
t.Fatal(err)
}
res, err := MarshalPKCS8PrivateKey(privateKey)
if err != nil {
t.Fatal(err)
}
privateKey1, err := ParsePKCS8PrivateKey(res)
if err != nil {
t.Fatal(err)
}
privateKey2, ok := privateKey1.(*sm9.SignPrivateKey)
if !ok {
t.Fatalf("not expected key")
}
if !privateKey.PrivateKey.Equal(privateKey2.PrivateKey) ||
!privateKey.MasterPublicKey.Equal(privateKey2.MasterPublicKey) {
t.Fatalf("not same key")
}
}
func TestMarshalPKCS8SM9EncPrivateKey(t *testing.T) {
masterKey, err := sm9.GenerateEncryptMasterKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
privateKey, err := masterKey.GenerateUserKey([]byte("emmansun"), 0x01)
if err != nil {
t.Fatal(err)
}
res, err := MarshalPKCS8PrivateKey(privateKey)
if err != nil {
t.Fatal(err)
}
privateKey1, err := ParsePKCS8PrivateKey(res)
if err != nil {
t.Fatal(err)
}
privateKey2, ok := privateKey1.(*sm9.EncryptPrivateKey)
if !ok {
t.Fatalf("not expected key")
}
if !privateKey.PrivateKey.Equal(privateKey2.PrivateKey) ||
!privateKey.MasterPublicKey.Equal(privateKey2.MasterPublicKey) {
t.Fatalf("not same key")
}
}
func TestMarshalPKCS8SM9SignMasterPrivateKey(t *testing.T) {
masterKey, err := sm9.GenerateSignMasterKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
res, err := MarshalPKCS8PrivateKey(masterKey)
if err != nil {
t.Fatal(err)
}
masterKey1, err := ParsePKCS8PrivateKey(res)
if err != nil {
t.Fatal(err)
}
masterKey2, ok := masterKey1.(*sm9.SignMasterPrivateKey)
if !ok {
t.Fatalf("not expected key")
}
masterKey2.MasterPublicKey.Marshal()
if !(masterKey.D.Cmp(masterKey2.D) == 0 && masterKey.MasterPublicKey.Equal(masterKey2.MasterPublicKey)) {
t.Fatalf("not same key")
}
}
func TestMarshalPKCS8SM9EncMasterPrivateKey(t *testing.T) {
masterKey, err := sm9.GenerateEncryptMasterKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
res, err := MarshalPKCS8PrivateKey(masterKey)
if err != nil {
t.Fatal(err)
}
masterKey1, err := ParsePKCS8PrivateKey(res)
if err != nil {
t.Fatal(err)
}
masterKey2, ok := masterKey1.(*sm9.EncryptMasterPrivateKey)
if !ok {
t.Fatalf("not expected key")
}
masterKey2.MasterPublicKey.Marshal()
if !(masterKey.D.Cmp(masterKey2.D) == 0 && masterKey.MasterPublicKey.Equal(masterKey2.MasterPublicKey)) {
t.Fatalf("not same key")
}
}
```
## 数字签名
使用用户签名私钥进行签名,使用签名主公钥和用户标识进行验签:
```go
func ExampleSignPrivateKey_Sign() {
// real user sign private key should be from secret storage.
kb, _ := hex.DecodeString("0130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4")
var b cryptobyte.Builder
b.AddASN1BigInt(new(big.Int).SetBytes(kb))
kb, _ = b.Bytes()
masterkey := new(sm9.SignMasterPrivateKey)
err := masterkey.UnmarshalASN1(kb)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from UnmarshalASN1: %s\n", err)
return
}
hid := byte(0x01)
uid := []byte("Alice")
userKey, err := masterkey.GenerateUserKey(uid, hid)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from GenerateUserKey: %s\n", err)
return
}
// sm9 sign
hash := []byte("Chinese IBS standard")
sig, err := userKey.Sign(rand.Reader, hash, nil)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from Sign: %s\n", err)
return
}
// Since sign is a randomized function, signature will be
// different each time.
fmt.Printf("%x\n", sig)
}
func ExampleVerifyASN1() {
// get master public key, can be from pem
masterPubKey := new(sm9.SignMasterPublicKey)
keyBytes, _ := hex.DecodeString("03818200049f64080b3084f733e48aff4b41b565011ce0711c5e392cfb0ab1b6791b94c40829dba116152d1f786ce843ed24a3b573414d2177386a92dd8f14d65696ea5e3269850938abea0112b57329f447e3a0cbad3e2fdb1a77f335e89e1408d0ef1c2541e00a53dda532da1a7ce027b7a46f741006e85f5cdff0730e75c05fb4e3216d")
err := masterPubKey.UnmarshalASN1(keyBytes)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from UnmarshalASN1: %s\n", err)
return
}
hid := byte(0x01)
uid := []byte("Alice")
hash := []byte("Chinese IBS standard")
sig, _ := hex.DecodeString("30660420b0d0c0bb1b57ea0d5b51cb5c96be850b8c2eef6b0fff5fcccb524b972574e6eb03420004901819575c9211c7b4e6e137794d23d0095608bcdad5c82dbff05777c5b49c763e4425acea2aaedf9e48d4784b4e4a5621cc3663fe0aae44dcbeac183fee9b0f")
ok := sm9.VerifyASN1(masterPubKey, uid, hid, hash, sig)
fmt.Printf("%v\n", ok)
// Output: true
}
func ExampleSignMasterPublicKey_Verify() {
// get master public key, can be from pem
masterPubKey := new(sm9.SignMasterPublicKey)
keyBytes, _ := hex.DecodeString("03818200049f64080b3084f733e48aff4b41b565011ce0711c5e392cfb0ab1b6791b94c40829dba116152d1f786ce843ed24a3b573414d2177386a92dd8f14d65696ea5e3269850938abea0112b57329f447e3a0cbad3e2fdb1a77f335e89e1408d0ef1c2541e00a53dda532da1a7ce027b7a46f741006e85f5cdff0730e75c05fb4e3216d")
err := masterPubKey.UnmarshalASN1(keyBytes)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from UnmarshalASN1: %s\n", err)
return
}
hid := byte(0x01)
uid := []byte("Alice")
hash := []byte("Chinese IBS standard")
sig, _ := hex.DecodeString("30660420b0d0c0bb1b57ea0d5b51cb5c96be850b8c2eef6b0fff5fcccb524b972574e6eb03420004901819575c9211c7b4e6e137794d23d0095608bcdad5c82dbff05777c5b49c763e4425acea2aaedf9e48d4784b4e4a5621cc3663fe0aae44dcbeac183fee9b0f")
ok := masterPubKey.Verify(uid, hid, hash, sig)
fmt.Printf("%v\n", ok)
// Output: true
}
```
签名结果ASN.1格式请参考参考《GB/T 41389-2022 信息安全技术 SM9密码算法使用规范》。
## 密钥封装
使用加密主公钥和目标用户标识进行密钥封装,使用用户加密私钥和用户标识进行解封:
```go
func ExampleEncryptMasterPublicKey_WrapKey() {
// get master public key, can be from pem
masterPubKey := new(sm9.EncryptMasterPublicKey)
keyBytes, _ := hex.DecodeString("03420004787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1")
err := masterPubKey.UnmarshalASN1(keyBytes)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from UnmarshalASN1: %s\n", err)
return
}
hid := byte(0x03)
uid := []byte("Bob")
key, cipherDer, err := masterPubKey.WrapKey(rand.Reader, uid, hid, 32)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from WrapKeyASN1: %s\n", err)
return
}
// Since WrapKey is a randomized function, result will be
// different each time.
fmt.Printf("%s %s\n", hex.EncodeToString(key), hex.EncodeToString(cipherDer))
}
func ExampleEncryptPrivateKey_UnwrapKey() {
// real user encrypt private key should be from secret storage, e.g. password protected pkcs8 file
kb, _ := hex.DecodeString("038182000494736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1")
userKey := new(sm9.EncryptPrivateKey)
err := userKey.UnmarshalASN1(kb)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from UnmarshalASN1: %s\n", err)
return
}
cipherDer, _ := hex.DecodeString("0342000447689629d1fa57e8def447f42b75e28518a1b692891528ca596f7bcbf581c7cf429ed01b114ce157ed4eadd0b2ded9a7e475e347f67b6affa3a6cf654573f978")
key, err := userKey.UnwrapKey([]byte("Bob"), cipherDer, 32)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from UnwrapKey: %s\n", err)
return
}
fmt.Printf("%s\n", hex.EncodeToString(key))
// Output: 270c42505bca90a8084064ea8af279364405a8195f30664082ead3d6991ed70f
}
```
密钥封装结果ASN.1格式请参考参考《GB/T 41389-2022 信息安全技术 SM9密码算法使用规范》。
## 公钥加密算法
使用加密主公钥和目标用户标识进行加密,使用用户加密私钥和用户标识进行解密:
```go
func ExampleEncryptMasterPublicKey_Encrypt() {
// get master public key, can be from pem
masterPubKey := new(sm9.EncryptMasterPublicKey)
keyBytes, _ := hex.DecodeString("03420004787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1")
err := masterPubKey.UnmarshalASN1(keyBytes)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from UnmarshalASN1: %s\n", err)
return
}
hid := byte(0x03)
uid := []byte("Bob")
ciphertext, err := masterPubKey.Encrypt(rand.Reader, uid, hid, []byte("Chinese IBE standard"), sm9.DefaultEncrypterOpts)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from Encrypt: %s\n", err)
return
}
// Since Encrypt is a randomized function, result will be
// different each time.
fmt.Printf("%s\n", hex.EncodeToString(ciphertext))
}
func ExampleEncryptPrivateKey_Decrypt() {
// real user encrypt private key should be from secret storage.
kb, _ := hex.DecodeString("038182000494736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1")
userKey := new(sm9.EncryptPrivateKey)
err := userKey.UnmarshalASN1(kb)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from UnmarshalASN1: %s\n", err)
return
}
uid := []byte("Bob")
cipherDer, _ := hex.DecodeString("307f020100034200042cb3e90b0977211597652f26ee4abbe275ccb18dd7f431876ab5d40cc2fc563d9417791c75bc8909336a4e6562450836cc863f51002e31ecf0c4aae8d98641070420638ca5bfb35d25cff7cbd684f3ed75f2d919da86a921a2e3e2e2f4cbcf583f240414b7e776811774722a8720752fb1355ce45dc3d0df")
plaintext, err := userKey.DecryptASN1(uid, cipherDer)
if err != nil {
fmt.Fprintf(os.Stderr, "Error from Decrypt: %s\n", err)
return
}
fmt.Printf("%s\n", plaintext)
// Output: Chinese IBE standard
}
```
密文封装结果ASN.1格式请参考参考《GB/T 41389-2022 信息安全技术 SM9密码算法使用规范》。
SM9公钥加密算法支持多种对称加密算法不像SM2公钥加密算法只支持XOR。不过由于非XOR对称加密算法有几个需要IV而规范没有定义所以会有互操作问题
* [关于SM9 非XOR加密标准问题](https://github.com/emmansun/gmsm/discussions/112)。
* 《GB/T 41389-2022 信息安全技术 SM9密码算法使用规范》6.1.5 加密数据格式。
## 密钥交换
在这里不详细介绍使用方法一般只有tls/tlcp才会用到普通应用通常不会涉及这一块请参考[API Document](https://godoc.org/github.com/emmansun/gmsm)。
## 性能
参考[SM9实现及优化](https://github.com/emmansun/gmsm/wiki/SM9%E5%AE%9E%E7%8E%B0%E5%8F%8A%E4%BC%98%E5%8C%96)。

226
docs/zuc.md Normal file
View File

@ -0,0 +1,226 @@
# 祖冲之序列密码算法应用指南
## 参考标准
* 《GB/T 33133.1-2016 信息安全技术 祖冲之序列密码算法 第1部分算法描述》
* 《GB/T 33133.2-2021 信息安全技术 祖冲之序列密码算法 第2部分保密性算法》
* 《GB/T 33133.3-2021 信息安全技术 祖冲之序列密码算法 第2部分完整性算法》
* [《祖冲之算法ZUC-256算法草案(中文)》](https://github.com/guanzhi/GM-Standards/blob/master/%E5%85%AC%E5%BC%80%E6%96%87%E6%A1%A3/%E7%A5%96%E5%86%B2%E4%B9%8B%E7%AE%97%E6%B3%95%EF%BC%9AZUC-256%E7%AE%97%E6%B3%95%E8%8D%89%E6%A1%88(%E4%B8%AD%E6%96%87).pdf)
您可以从[国家标准全文公开系统](https://openstd.samr.gov.cn/)在线阅读这些标准。
## 保密性算法
保密性算法EEA实现了```cipher.Stream```接口,所以和其它流密码算法使用类似,只是创建方法不同而已。
| | ZUC-128 | ZUC-256 |
| :--- | :--- | :--- |
| Key字节数 | 16 | 32 |
| IV字节数 | 16 | 23 |
```go
func ExampleNewCipher() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("some plaintext")
const ivSize = zuc.IVSize128
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, ivSize+len(plaintext))
iv := ciphertext[:ivSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream, err := zuc.NewCipher(key, iv)
if err != nil {
panic(err)
}
stream.XORKeyStream(ciphertext[ivSize:], plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
// Stream cipher is the same for both encryption and decryption, so we can
// also decrypt that ciphertext with NewCTR.
plaintext2 := make([]byte, len(plaintext))
stream, err = zuc.NewCipher(key, iv)
if err != nil {
panic(err)
}
stream.XORKeyStream(plaintext2, ciphertext[ivSize:])
fmt.Printf("%s\n", plaintext2)
// Output: some plaintext
}
func ExampleNewCipher_zuc256() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373")
plaintext := []byte("some plaintext")
const ivSize = zuc.IVSize256
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, ivSize+len(plaintext))
iv := ciphertext[:ivSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream, err := zuc.NewCipher(key, iv)
if err != nil {
panic(err)
}
stream.XORKeyStream(ciphertext[ivSize:], plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
// Stream cipher is the same for both encryption and decryption, so we can
// also decrypt that ciphertext with NewCTR.
plaintext2 := make([]byte, len(plaintext))
stream, err = zuc.NewCipher(key, iv)
if err != nil {
panic(err)
}
stream.XORKeyStream(plaintext2, ciphertext[ivSize:])
fmt.Printf("%s\n", plaintext2)
// Output: some plaintext
}
```
### Seekable Stream
完整性算法支持Seekable Stream也就是随机定位到某点进行处理内部实现了分桶缓存状态每个状态的大小大概是88字节`bucketSize`的大小可以结合要处理的流大小以及内存占用来平衡考虑。同时,`bucketSize`内部会被处理成128字节的倍数以利于实现。
如果您没有对同一个流反复进行**前进**、**后退**加解密的需求,可以使用`NewCipher`或者`NewEEACipher`方法,避免内部状态缓存。
## 完整性算法
完整性算法实现了```hash.Hash```接口,所以其使用方法和其它哈希算法类似。
| | ZUC-128 | ZUC-256 |
| :--- | :--- | :--- |
| Key字节数 | 16 | 32 |
| IV字节数 | 16 | 23 |
| MAC字节数 | 4 | 4/8/16 |
```go
func ExampleNewHash() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
// iv should be generated randomly
iv, _ := hex.DecodeString("6368616e676520746869732070617373")
h, err := zuc.NewHash(key, iv)
if err != nil {
panic(err)
}
h.Write([]byte("hello world\n"))
fmt.Printf("%x", h.Sum(nil))
// Output: c43cd26a
}
func ExampleNewHash256_tagSize4() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373")
// iv should be generated randomly
iv, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520")
h, err := zuc.NewHash256(key, iv, 4)
if err != nil {
panic(err)
}
h.Write([]byte("hello world\n"))
fmt.Printf("%x", h.Sum(nil))
// Output: b76f96ed
}
func ExampleNewHash256_tagSize8() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373")
// iv should be generated randomly
iv, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520")
h, err := zuc.NewHash256(key, iv, 8)
if err != nil {
panic(err)
}
h.Write([]byte("hello world\n"))
fmt.Printf("%x", h.Sum(nil))
// Output: f28aea6c9db3dc69
}
func ExampleNewHash256_tagSize16() {
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373")
// iv should be generated randomly
iv, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520")
h, err := zuc.NewHash256(key, iv, 16)
if err != nil {
panic(err)
}
h.Write([]byte("hello world\n"))
fmt.Printf("%x", h.Sum(nil))
// Output: fd8d10ea65b6369cccc07d50b4657d84
}
```
要支持位为单位的话,可以调用```Finish```方法。
```go
func ExampleZUC128Mac_Finish() {
key := make([]byte, 16)
iv := make([]byte, 16)
h, err := zuc.NewHash(key, iv)
if err != nil {
panic(err)
}
fmt.Printf("%x", h.Finish([]byte{0}, 1))
// Output: c8a9595e
}
func ExampleZUC128Mac_Finish_mixed() {
key := []byte{
0xc9, 0xe6, 0xce, 0xc4, 0x60, 0x7c, 0x72, 0xdb,
0x00, 0x0a, 0xef, 0xa8, 0x83, 0x85, 0xab, 0x0a,
}
// iv should be generated randomly
iv, _ := hex.DecodeString("a94059da50000000294059da50008000")
h, err := zuc.NewHash(key, iv)
if err != nil {
panic(err)
}
in, _ := hex.DecodeString("983b41d47d780c9e1ad11d7eb70391b1de0b35da2dc62f83e7b78d6306ca0ea07e941b7be91348f9fcb170e2217fecd97f9f68adb16e5d7d21e569d280ed775cebde3f4093c53881")
h.Write(in)
fmt.Printf("%x", h.Finish([]byte{0}, 1))
// Output: fae8ff0b
}
```

294
drbg/common.go Normal file
View File

@ -0,0 +1,294 @@
// Package drbg implements Random Number Generation Using Deterministic Random Bit Generators.
package drbg
import (
"crypto/cipher"
"crypto/rand"
"errors"
"hash"
"io"
"time"
"github.com/emmansun/gmsm/sm3"
"github.com/emmansun/gmsm/sm4"
)
const (
reseedCounterIntervalLevelTest = uint64(8)
reseedCounterIntervalLevel2 = 1 << 10
reseedCounterIntervalLevel1 = 1 << 20
reseedTimeIntervalLevelTest = time.Duration(6) * time.Second
reseedTimeIntervalLevel2 = time.Duration(60) * time.Second
reseedTimeIntervalLevel1 = time.Duration(600) * time.Second
maxBytes = 1 << 27
maxBytesPerGenerate = 1 << 11
)
var ErrReseedRequired = errors.New("drbg: reseed reuqired")
type SecurityLevel byte
const (
SECURITY_LEVEL_ONE SecurityLevel = 0x01
SECURITY_LEVEL_TWO SecurityLevel = 0x02
SECURITY_LEVEL_TEST SecurityLevel = 0x99
)
// DrbgPrng sample pseudo random number generator base on DRBG
type DrbgPrng struct {
entropySource io.Reader
securityStrength int
impl DRBG
}
// NewCtrDrbgPrng create pseudo random number generator base on CTR DRBG
func NewCtrDrbgPrng(cipherProvider func(key []byte) (cipher.Block, error), keyLen int, entropySource io.Reader, securityStrength int, gm bool, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) {
prng := new(DrbgPrng)
if entropySource != nil {
prng.entropySource = entropySource
} else {
prng.entropySource = rand.Reader
}
prng.securityStrength = selectSecurityStrength(securityStrength)
if gm && securityStrength < 32 {
return nil, errors.New("drbg: invalid security strength")
}
// Get entropy input
entropyInput := make([]byte, prng.securityStrength)
err := prng.getEntropy(entropyInput)
if err != nil {
return nil, err
}
// Get nonce, reference to NIST SP 800-90A, 8.6.7
nonce := make([]byte, prng.securityStrength/2)
err = prng.getEntropy(nonce)
if err != nil {
return nil, err
}
// initial working state
prng.impl, err = NewCtrDrbg(cipherProvider, keyLen, securityLevel, gm, entropyInput, nonce, personalization)
if err != nil {
return nil, err
}
return prng, nil
}
// NewNistCtrDrbgPrng create pseudo random number generator base on CTR DRBG which follows NIST standard
func NewNistCtrDrbgPrng(cipherProvider func(key []byte) (cipher.Block, error), keyLen int, entropySource io.Reader, securityStrength int, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) {
return NewCtrDrbgPrng(cipherProvider, keyLen, entropySource, securityStrength, false, securityLevel, personalization)
}
// NewNistCtrDrbgPrng create pseudo random number generator base on CTR DRBG which follows GM/T 0105-2021 standard
func NewGmCtrDrbgPrng(entropySource io.Reader, securityStrength int, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) {
return NewCtrDrbgPrng(sm4.NewCipher, 16, entropySource, securityStrength, true, securityLevel, personalization)
}
// NewHashDrbgPrng create pseudo random number generator base on HASH DRBG
func NewHashDrbgPrng(newHash func() hash.Hash, entropySource io.Reader, securityStrength int, gm bool, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) {
prng := new(DrbgPrng)
if entropySource != nil {
prng.entropySource = entropySource
} else {
prng.entropySource = rand.Reader
}
prng.securityStrength = selectSecurityStrength(securityStrength)
if gm && securityStrength < 32 {
return nil, errors.New("drbg: invalid security strength")
}
// Get entropy input
entropyInput := make([]byte, prng.securityStrength)
err := prng.getEntropy(entropyInput)
if err != nil {
return nil, err
}
// Get nonce, reference to NIST SP 800-90A, 8.6.7
nonce := make([]byte, prng.securityStrength/2)
err = prng.getEntropy(nonce)
if err != nil {
return nil, err
}
// initial working state
prng.impl, err = NewHashDrbg(newHash, securityLevel, gm, entropyInput, nonce, personalization)
if err != nil {
return nil, err
}
return prng, nil
}
// NewNistHashDrbgPrng create pseudo random number generator base on hash DRBG which follows NIST standard
func NewNistHashDrbgPrng(newHash func() hash.Hash, entropySource io.Reader, securityStrength int, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) {
return NewHashDrbgPrng(newHash, entropySource, securityStrength, false, securityLevel, personalization)
}
// NewGmHashDrbgPrng create pseudo random number generator base on hash DRBG which follows GM/T 0105-2021 standard
func NewGmHashDrbgPrng(entropySource io.Reader, securityStrength int, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) {
return NewHashDrbgPrng(sm3.New, entropySource, securityStrength, true, securityLevel, personalization)
}
// NewHmacDrbgPrng create pseudo random number generator base on hash mac DRBG
func NewHmacDrbgPrng(newHash func() hash.Hash, entropySource io.Reader, securityStrength int, gm bool, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) {
prng := new(DrbgPrng)
if entropySource != nil {
prng.entropySource = entropySource
} else {
prng.entropySource = rand.Reader
}
prng.securityStrength = selectSecurityStrength(securityStrength)
// Get entropy input
entropyInput := make([]byte, prng.securityStrength)
err := prng.getEntropy(entropyInput)
if err != nil {
return nil, err
}
// Get nonce, reference to NIST SP 800-90A, 8.6.7
nonce := make([]byte, prng.securityStrength/2)
err = prng.getEntropy(nonce)
if err != nil {
return nil, err
}
// initial working state
prng.impl, err = NewHmacDrbg(newHash, securityLevel, gm, entropyInput, nonce, personalization)
if err != nil {
return nil, err
}
return prng, nil
}
// NewNistHmacDrbgPrng create pseudo random number generator base on hash mac DRBG which follows NIST standard
func NewNistHmacDrbgPrng(newHash func() hash.Hash, entropySource io.Reader, securityStrength int, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) {
return NewHmacDrbgPrng(newHash, entropySource, securityStrength, false, securityLevel, personalization)
}
func (prng *DrbgPrng) getEntropy(entropyInput []byte) error {
n, err := prng.entropySource.Read(entropyInput)
if err != nil {
return err
}
if n != len(entropyInput) {
return errors.New("drbg: fail to read enough entropy input")
}
return nil
}
func (prng *DrbgPrng) Read(data []byte) (int, error) {
maxBytesPerRequest := prng.impl.MaxBytesPerRequest()
total := 0
for len(data) > 0 {
b := data
if len(data) > maxBytesPerRequest {
b = data[:maxBytesPerRequest]
}
err := prng.impl.Generate(b, nil)
if err == ErrReseedRequired {
entropyInput := make([]byte, prng.securityStrength)
err := prng.getEntropy(entropyInput)
if err != nil {
return 0, err
}
err = prng.impl.Reseed(entropyInput, nil)
if err != nil {
return 0, err
}
} else if err != nil {
return 0, err
} else {
total += len(b)
data = data[len(b):]
}
}
return total, nil
}
// DRBG interface for both hash and ctr drbg implementations
type DRBG interface {
// check internal state, return if reseed required
NeedReseed() bool
// reseed process
Reseed(entropy, additional []byte) error
// generate requrested bytes to b
Generate(b, additional []byte) error
// MaxBytesPerRequest return max bytes per request
MaxBytesPerRequest() int
}
type BaseDrbg struct {
v []byte
seedLength int
reseedTime time.Time
reseedIntervalInTime time.Duration
reseedCounter uint64
reseedIntervalInCounter uint64
securityLevel SecurityLevel
gm bool
}
func (hd *BaseDrbg) NeedReseed() bool {
return (hd.reseedCounter > hd.reseedIntervalInCounter) || (hd.gm && time.Since(hd.reseedTime) > hd.reseedIntervalInTime)
}
func (hd *BaseDrbg) setSecurityLevel(securityLevel SecurityLevel) {
hd.securityLevel = securityLevel
switch securityLevel {
case SECURITY_LEVEL_TWO:
hd.reseedIntervalInCounter = reseedCounterIntervalLevel2
hd.reseedIntervalInTime = reseedTimeIntervalLevel2
case SECURITY_LEVEL_TEST:
hd.reseedIntervalInCounter = reseedCounterIntervalLevelTest
hd.reseedIntervalInTime = reseedTimeIntervalLevelTest
default:
hd.reseedIntervalInCounter = reseedCounterIntervalLevel1
hd.reseedIntervalInTime = reseedTimeIntervalLevel1
}
}
// Set security_strength to the lowest security strength greater than or equal to
// requested_instantiation_security_strength from the set {112, 128, 192, 256}.
func selectSecurityStrength(requested int) int {
switch {
case requested <= 14:
return 14
case requested <= 16:
return 16
case requested <= 24:
return 24
case requested <= 32:
return 32
default:
return requested
}
}
func add(left, right []byte, len int) {
var temp uint16 = 0
for i := len - 1; i >= 0; i-- {
temp += uint16(left[i]) + uint16(right[i])
right[i] = byte(temp & 0xff)
temp >>= 8
}
}
func addOne(data []byte, len int) {
var temp uint16 = 1
for i := len - 1; i >= 0; i-- {
temp += uint16(data[i])
data[i] = byte(temp & 0xff)
temp >>= 8
}
}

123
drbg/common_test.go Normal file
View File

@ -0,0 +1,123 @@
package drbg
import (
"bytes"
"crypto/aes"
"crypto/sha256"
"testing"
)
func TestGmCtrDrbgPrng(t *testing.T) {
prng, err := NewGmCtrDrbgPrng(nil, 32, SECURITY_LEVEL_TEST, nil)
if err != nil {
t.Fatal(err)
}
data := make([]byte, 33)
for i := 0; i < int(reseedCounterIntervalLevelTest+1); i++ {
n, err := prng.Read(data)
if err != nil {
t.Fatal(err)
}
if n != 33 {
t.Errorf("not got enough random bytes")
}
}
}
func TestGmCtrDrbgPrngReseedCase(t *testing.T) {
prng, err := NewGmCtrDrbgPrng(nil, 32, SECURITY_LEVEL_TEST, nil)
if err != nil {
t.Fatal(err)
}
data := make([]byte, 64)
for i := 0; i < int(reseedCounterIntervalLevelTest+1); i++ {
for j := 0; j < 64; j++ {
data[j] = 0
}
n, err := prng.Read(data)
if err != nil {
t.Fatal(err)
}
if n != 64 {
t.Errorf("not got enough random bytes")
}
if bytes.Contains(data, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) {
t.Fatal("failed, it's a bug")
}
}
}
func TestNistCtrDrbgPrng(t *testing.T) {
prng, err := NewNistCtrDrbgPrng(aes.NewCipher, 16, nil, 16, SECURITY_LEVEL_TEST, nil)
if err != nil {
t.Fatal(err)
}
data := make([]byte, maxBytesPerGenerate+1)
n, err := prng.Read(data)
if err != nil {
t.Fatal(err)
}
if n != maxBytesPerGenerate+1 {
t.Errorf("not got enough random bytes")
}
}
func TestGmHashDrbgPrng(t *testing.T) {
prng, err := NewGmHashDrbgPrng(nil, 32, SECURITY_LEVEL_TEST, nil)
if err != nil {
t.Fatal(err)
}
data := make([]byte, 33)
for i := 0; i < int(reseedCounterIntervalLevelTest+1); i++ {
n, err := prng.Read(data)
if err != nil {
t.Fatal(err)
}
if n != 33 {
t.Errorf("not got enough random bytes")
}
}
}
func TestNistHashDrbgPrng(t *testing.T) {
prng, err := NewNistHashDrbgPrng(sha256.New, nil, 32, SECURITY_LEVEL_TEST, nil)
if err != nil {
t.Fatal(err)
}
data := make([]byte, maxBytesPerGenerate+1)
n, err := prng.Read(data)
if err != nil {
t.Fatal(err)
}
if n != maxBytesPerGenerate+1 {
t.Errorf("not got enough random bytes")
}
}
func TestNistHmacDrbgPrng(t *testing.T) {
prng, err := NewNistHmacDrbgPrng(sha256.New, nil, 32, SECURITY_LEVEL_TEST, nil)
if err != nil {
t.Fatal(err)
}
data := make([]byte, maxBytesPerGenerate+1)
n, err := prng.Read(data)
if err != nil {
t.Fatal(err)
}
if n != maxBytesPerGenerate+1 {
t.Errorf("not got enough random bytes")
}
}
func TestGMSecurityStrengthValidation(t *testing.T) {
_, err := NewGmHashDrbgPrng(nil, 24, SECURITY_LEVEL_TEST, nil)
if err == nil {
t.Fatalf("expected error here")
}
_, err = NewGmCtrDrbgPrng(nil, 24, SECURITY_LEVEL_TEST, nil)
if err == nil {
t.Fatalf("expected error here")
}
}

224
drbg/ctr_drbg.go Normal file
View File

@ -0,0 +1,224 @@
package drbg
import (
"crypto/cipher"
"crypto/subtle"
"errors"
"time"
"github.com/emmansun/gmsm/internal/byteorder"
"github.com/emmansun/gmsm/sm4"
)
// CtrDrbg CTR DRBG structure, its instance is NOT goroutine safe!!!
type CtrDrbg struct {
BaseDrbg
cipherProvider func(key []byte) (cipher.Block, error)
key []byte
keyLen int
}
// NewCtrDrbg create one CTR DRBG instance
func NewCtrDrbg(cipherProvider func(key []byte) (cipher.Block, error), keyLen int, securityLevel SecurityLevel, gm bool, entropy, nonce, personalization []byte) (*CtrDrbg, error) {
hd := &CtrDrbg{}
hd.gm = gm
hd.setSecurityLevel(securityLevel)
// here for the min length, we just check <=0 now
if len(entropy) == 0 || (hd.gm && len(entropy) < 32) || len(entropy) >= maxBytes {
return nil, errors.New("drbg: invalid entropy length")
}
// here for the min length, we just check <=0 now
if len(nonce) == 0 || (hd.gm && len(nonce) < 16) || len(nonce) >= maxBytes>>1 {
return nil, errors.New("drbg: invalid nonce length")
}
if len(personalization) >= maxBytes {
return nil, errors.New("drbg: personalization is too long")
}
hd.cipherProvider = cipherProvider
hd.keyLen = keyLen
temp := make([]byte, hd.keyLen)
block, err := cipherProvider(temp)
if err != nil {
return nil, err
}
hd.seedLength = block.BlockSize() + keyLen
hd.v = make([]byte, block.BlockSize())
hd.key = make([]byte, hd.keyLen)
// seed_material = entropy_input || instantiation_nonce || personalization_string
seedMaterial := make([]byte, len(entropy)+len(nonce)+len(personalization))
copy(seedMaterial, entropy)
copy(seedMaterial[len(entropy):], nonce)
copy(seedMaterial[len(entropy)+len(nonce):], personalization)
// seed_material = Block_Cipher_df(seed_material, seed_length)
seedMaterial = hd.derive(seedMaterial, hd.seedLength)
// CTR_DRBG_Updae(seed_material, Key, V)
hd.update(seedMaterial)
hd.reseedCounter = 1
hd.reseedTime = time.Now()
return hd, nil
}
// NewNISTCtrDrbg create one CTR DRBG implementation which follows NIST standard
func NewNISTCtrDrbg(cipherProvider func(key []byte) (cipher.Block, error), keyLen int, securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*CtrDrbg, error) {
return NewCtrDrbg(cipherProvider, keyLen, securityLevel, false, entropy, nonce, personalization)
}
// NewGMCtrDrbg create one CTR DRBG implementation which follows GM/T 0105-2021 standard
func NewGMCtrDrbg(securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*CtrDrbg, error) {
return NewCtrDrbg(sm4.NewCipher, 16, securityLevel, true, entropy, nonce, personalization)
}
func (cd *CtrDrbg) Reseed(entropy, additional []byte) error {
// here for the min length, we just check <=0 now
if len(entropy) == 0 || (cd.gm && len(entropy) < 32) || len(entropy) >= maxBytes {
return errors.New("drbg: invalid entropy length")
}
if len(additional) >= maxBytes {
return errors.New("drbg: additional input too long")
}
// seed_material = entropy_input || additional_input
var seedMaterial []byte
if len(additional) == 0 {
seedMaterial = entropy
} else {
seedMaterial = make([]byte, len(entropy)+len(additional))
copy(seedMaterial, entropy)
copy(seedMaterial[len(entropy):], additional)
}
// seed_material = Block_Cipher_df(seed_material, seed_length)
seedMaterial = cd.derive(seedMaterial, cd.seedLength)
// CTR_DRBG_Updae(seed_material, Key, V)
cd.update(seedMaterial)
cd.reseedCounter = 1
cd.reseedTime = time.Now()
return nil
}
func (cd *CtrDrbg) newBlockCipher(key []byte) cipher.Block {
block, err := cd.cipherProvider(key)
if err != nil {
panic(err)
}
return block
}
func (cd *CtrDrbg) MaxBytesPerRequest() int {
if cd.gm {
return len(cd.v)
}
return maxBytesPerGenerate
}
// Generate CTR DRBG pseudorandom bits generate process.
func (cd *CtrDrbg) Generate(out, additional []byte) error {
if cd.NeedReseed() {
return ErrReseedRequired
}
outlen := len(cd.v)
if (cd.gm && len(out) > outlen) || (!cd.gm && len(out) > maxBytesPerGenerate) {
return errors.New("drbg: too many bytes requested")
}
// If len(additional_input) > 0, then
// additional_input = Block_Cipher_df(additional_input, seed_length)
// CTR_DRBG_Update(additional_input, Key, V)
if len(additional) > 0 {
additional = cd.derive(additional, cd.seedLength)
cd.update(additional)
}
block := cd.newBlockCipher(cd.key)
temp := make([]byte, outlen)
m := len(out)
limit := uint64(m+outlen-1) / uint64(outlen)
for i := range int(limit) {
// V = (V + 1) mod 2^outlen)
addOne(cd.v, outlen)
// output_block = Encrypt(Key, V)
block.Encrypt(temp, cd.v)
copy(out[i*outlen:], temp)
}
cd.update(additional)
cd.reseedCounter++
return nil
}
func (cd *CtrDrbg) update(seedMaterial []byte) {
temp := make([]byte, cd.seedLength)
block := cd.newBlockCipher(cd.key)
outlen := block.BlockSize()
v := make([]byte, outlen)
output := make([]byte, outlen)
copy(v, cd.v)
for i := range (cd.seedLength+outlen-1)/outlen {
// V = (V + 1) mod 2^outlen
addOne(v, outlen)
// output_block = Encrypt(Key, V)
block.Encrypt(output, v)
copy(temp[i*outlen:], output)
}
// temp = temp XOR seed_material
subtle.XORBytes(temp, temp, seedMaterial)
// Key = leftmost(temp, key_length)
copy(cd.key, temp)
// V = rightmost(temp, outlen)
copy(cd.v, temp[cd.keyLen:])
}
// derive Block_Cipher_df
func (cd *CtrDrbg) derive(seedMaterial []byte, returnBytes int) []byte {
outlen := cd.seedLength - cd.keyLen
lenS := ((4 + 4 + len(seedMaterial) + outlen) / outlen) * outlen
S := make([]byte, lenS+outlen)
// S = counter || len(seed_material) || len(return_bytes) || seed_material || 0x80
// len(S) = ((outlen + 4 + 4 + len(seed_material) + 1 + outlen - 1) / outlen) * outlen
byteorder.BEPutUint32(S[outlen:], uint32(len(seedMaterial)))
byteorder.BEPutUint32(S[outlen+4:], uint32(returnBytes))
copy(S[outlen+8:], seedMaterial)
S[outlen+8+len(seedMaterial)] = 0x80
key := make([]byte, cd.keyLen)
for i := range cd.keyLen {
key[i] = byte(i)
}
blocks := (cd.seedLength + outlen - 1) / outlen
temp := make([]byte, blocks*outlen)
block := cd.newBlockCipher(key)
for i := 0; i < blocks; i++ {
byteorder.BEPutUint32(S, uint32(i))
copy(temp[i*outlen:], cd.bcc(block, S))
}
key = temp[:cd.keyLen]
X := temp[cd.keyLen:cd.seedLength]
temp = make([]byte, returnBytes)
block = cd.newBlockCipher(key)
for i := 0; i < (returnBytes+outlen-1)/outlen; i++ {
block.Encrypt(X, X)
copy(temp[i*outlen:], X)
}
return temp
}
func (cd *CtrDrbg) bcc(block cipher.Block, data []byte) []byte {
chainingValue := make([]byte, block.BlockSize())
for i := 0; i < len(data)/block.BlockSize(); i++ {
subtle.XORBytes(chainingValue, chainingValue, data[i*block.BlockSize():])
block.Encrypt(chainingValue, chainingValue)
}
return chainingValue
}

305
drbg/ctr_drbg_test.go Normal file
View File

@ -0,0 +1,305 @@
package drbg
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"testing"
"github.com/emmansun/gmsm/sm4"
)
var ctrtests = []struct {
gm bool
cipherProvider func(key []byte) (cipher.Block, error)
keyLen int
entropyInput string
nonce string
personalizationString string
v0 string
key0 string
entropyInputReseed string
additionalInputReseed string
v1 string
key1 string
additionalInput1 string
v2 string
key2 string
additionalInput2 string
returnbits1 string
v3 string
key3 string
}{
{ // AES-128, without additional input
false,
aes.NewCipher,
16,
"0f65da13dca407999d4773c2b4a11d85",
"5209e5b4ed82a234",
"",
"80941680713df715056fb2a3d2e998b2",
"0c42ea6804303954deb197a07e6dbdd2",
"1dea0a12c52bf64339dd291c80d8ca89",
"",
"f2bacbb233252fba35fb0582f9286179", // v1
"32fbfd0109f364ed21ef21a6e5c763e7", //key1
"",
"99003d630bba500fe17c37f8c7331bf6", // v2
"757c8eb766f9aaa4650d6500b58624a3", //key2
"",
"2859cc468a76b08661ffd23b28547ffd0997ad526a0f51261b99ed3a37bd407bf418dbe6c6c3e26ed0ddefcb7474d899bd99f3655427519fc5b4057bcaf306d4",
"5907ab447a88e5106753507cc97e0fd5",
"e421ff2445e04992faf36cf9a5eaf1f9",
},
{ // AES-128, without additional input
false,
aes.NewCipher,
16,
"c9b8d7eb0afa5889e7f9b78a50ed453c",
"3058ba347ecd11b1",
"",
"b4e0180e3af0d99592249db33a29cc4e",
"1621bebef7e9215078459ecc74baffbc",
"643686b86266d9111f29eb389e1184b4",
"",
"7574911eeb85d56d385f0c8c99965c4a", // v1
"a4c515266cb5986825a503b39d5f398c", //key1
"",
"abca3ea049e405d3826f43e54e08c8f7", // v2
"edcdf23f60d3988a4d235798aa0d33a2", //key2
"",
"0a8ccadc1c5cbd20b8ce32f942505e654b91a4e9410e0ea627c961d632d3be71d6a7dfd64b8f70d28ff91869b92ced908b454936b6d18fcddd7fb77216ccc404",
"1d57b4e09fd920d91877a0737559ee29",
"e83e07722d26779d0b76a52a629b211b",
},
{ // AES-128, with additional input
false,
aes.NewCipher,
16,
"285da6cf762552634636bfee3400b156",
"8f8bada74820cb43",
"",
"ad2af7e4c84337cfc3116d59f02c54a8", // v0
"c92780982442d348cc7363dfc96a999d", // key0
"b4699b33354a83bfed115f770f32db0b", // EntropyInputReseed
"38bfec9a10e6e40c106841dae48dc3b8", // AdditionalInputReseed
"923f37427a8e10bf945249a5b790769a", // v1
"57004c8a776f5c702e83ff56acc32dcc", // key1
"629ead5bacfac8235711ffeb22f57558", // AdditionalInput1
"7ade619ed91092987d8a1d244605f85f", // v2
"3b5f92f511c10fef2f640de2cd8c9049", // key2
"dd8a02ee668ca3e03949b38cb6e6b4df", // AdditionalInput2
"e555aa4432bde04dcf0f0b03ead187b31df06653d444234b5c1bfc11b224285f2fb2b6cdd5a9ae6f13d99bd02c3c9fe9c3c1be46a600f5f757ab4574af893501",
"f5dac2375e820f797c6f1258147d8ea7", // v3
"6bc01c1518fe9f9dfbbb08d97c34db1e", // key3
},
{ // AES-192, without additional input
false,
aes.NewCipher,
24,
"b11d8b104a7ced9b9f37e5d92ad3dfcbb817552b1ae88f6a",
"017510f270c66586a51313eadc32b07e",
"",
"9e5767ab537fe663c71e4054ba618c8d", // v0
"b9b3d73bc0c784a7d78db344109707c73abbff7dc2dfa864", // key0
"6d14cfb36f30c9c1a1ba0e0a32c2f99d1b47f219a3a8ac14", // EntropyInputReseed
"", // AdditionalInputReseed
"c8563c5a4adc3b579f79f898c4b69854", // v1
"3e18d4984d454e5f986e49bfa7a569dab3667ece8130cba1", // key1
"", // AdditionalInput1
"087a3112e191f60619acae2a556f333b", // v2
"b42a24cbb9e8c014bb65350afa28a67b273a41e599bde5b8", // key2
"", // AdditionalInput2
"53fbba563ae014ebc080767aab8452a9f36ce40bbf68f1a12dc0a6388c870c8dfa4250526cbc8c983fee6449903c6bd7c2c02e327680a66b464267edbc4e6797",
"84f344f8277841e920464ca475b10276", // v3
"1f5e987ac2259b7072867e4ae59167094d0162111062f6f8", // key3
},
{ // AES-192, with additional input
false,
aes.NewCipher,
24,
"3a09c9cc5e01f152ea2ed3021d49b4d6386aa6f04521ebde",
"490bd4ee628cf9615035543e70fce4e2",
"",
"59a45ccbc3864f79b896c30d4a231d46", // v0
"a4283dc9450ac97bf22c387082e3816728243473cedaa2af", // key0
"df06e5668d41a6fa7660aef477eff7a0ffc0542c1cd406d5", // EntropyInputReseed
"59b8c26626aab69e462752722f19450d12e2c0e959882d4d06ef4177e396855d", // AdditionalInputReseed
"5857d49a1552923931926dca1682fbc2", // v1
"9c4d7784fe341619e21f2535d404866df3b75e9a7940d471", // key1
"28e57a9128e479985cce391e98127fd126f37ad0f317fd5f97b8c18e762f360b", // AdditionalInput1
"bb8ed7bcbe1203be861b8e6570fe116b", // v2
"6a8fddde995255f89ea3c9454cc481045ff0e16ce5a34693", // key2
"d488672b52e867816178369f542190685bbe8672720c1943d8a4378cc9b9dd0c", // AdditionalInput2
"5c233e2850e4981bab0f6513a76ca2c9f9f97b89b7fedd3d9aaffecf305d89fd5306cf24715895ad9ba7dac8c389fd87f95b4973003150871fa281e962f270cb",
"1cf82a0638c421bb43401943498d0f88", // v3
"5dec9ad1f5f3d0e7bb59ae581097a3f616e443e4f5bd804a", // key3
},
{ // AES-256, without additional input
false,
aes.NewCipher,
32,
"2d4c9f46b981c6a0b2b5d8c69391e569ff13851437ebc0fc00d616340252fed5",
"0bf814b411f65ec4866be1abb59d3c32",
"",
"446ce986bd722ad1a514ebb7d274ec99", // v0
"d64160c3e965f377caef625c7eb21dd37728bcf84bfc23b92e267611feaffda8", // key0
"93500fae4fa32b86033b7a7bac9d37e710dcc67ca266bc8607d665937766d207", // EntropyInputReseed
"", // AdditionalInputReseed
"0b8e38a54036f1ba80a2880d4f17bb09", // v1
"50d9feb33fc77303b83232b7deded04f1bfa4afaa937712f88458d6b64c046c5", // key1
"", // AdditionalInput1
"84b0a849c5459e27fe7f8c5db26fa13d", // v2
"a2203a6f082ecdc0cd38f0b3b19f1a8cd6a5f110a13bb488c1e70f9f95a93024", // key2
"", // AdditionalInput2
"322dd28670e75c0ea638f3cb68d6a9d6e50ddfd052b772a7b1d78263a7b8978b6740c2b65a9550c3a76325866fa97e16d74006bc96f26249b9f0a90d076f08e5",
"de67dd5f9a431fc46dd1825cd1a2bff3", // v3
"de721178a341a85eb54a2f7e2b3cd4bcc201417e739eb183fa958f9af8535b2c", // key3
},
{ // AES-256, with additional input
false,
aes.NewCipher,
32,
"6f60f0f9d486bc23e1223b934e61c0c78ae9232fa2e9a87c6dacd447c3f10e9e",
"401e3f87762fa8a14ab232ccb8480a2f",
"",
"ee534dcfd9d2be3a3f9c65a6c5f599b0", // v0
"6d9aa2e029466438d3e4c22530bd071dbe57b549b87370957b28da8ae083f8d6", // key0
"350be52552a65a804a106543ebb7dd046cffae104e4e8b2f18936d564d3c1950", // EntropyInputReseed
"7a3688adb1cfb6c03264e2762ece96bfe4daf9558fabf74d7fff203c08b4dd9f", // AdditionalInputReseed
"433725f6c4b8c662c3b2db4b75f38d86", // v1
"b5953178a900b2fcf052b5cbc1d882ea944da2965e84fef59c4919bb4d5c892d", // key1
"67cf4a56d081c53670f257c25557014cd5e8b0e919aa58f23d6861b10b00ea80", // AdditionalInput1
"2c342b2ab12bd3484e4660b8dd5f85eb", // v2
"b2b9e9f1ffcfd84c050445f93dfad90d6ca240494bbed5d44a0deb38fbaeb751", // key2
"648d4a229198b43f33dd7dd8426650be11c5656adcdf913bb3ee5eb49a2a3892", // AdditionalInput2
"2d819fb9fee38bfc3f15a07ef0e183ff36db5d3184cea1d24e796ba103687415abe6d9f2c59a11931439a3d14f45fc3f4345f331a0675a3477eaf7cd89107e37",
"a9729f842063b9464e74018c0ab30df3", // v3
"770600434fe0af64e045f5530e2b9732da9e3b4c3af342994a4f1f7ee5c4144e", // key3
},
{ // SM4-128, without additional input
true,
sm4.NewCipher,
16,
"2d4c9f46b981c6a0b2b5d8c69391e569ff13851437ebc0fc00d616340252fed5",
"0bf814b411f65ec4866be1abb59d3c32",
"",
"044f9ff3b7e8ad2b60a7b2c05fe6b5b7",
"7fce60b97d8ceb60506bff1d37b1a936",
"93500fae4fa32b86033b7a7bac9d37e710dcc67ca266bc8607d665937766d207",
"",
"8bd44b2e39f8186497f889c73555797d", // v1
"02b9a8f88124bd9cec909e1fd7ec9971", //key1
"",
"fbc91ad876ba3a84588be2f358b9e13c", // v2
"4804b2a1a971ca729abff5bada051cf6", //key2
"",
"e732a524de8ad239aa293ac8ae588f9d",
"ce60250d77048bdbe48ade354b6869f6",
"6788e31ae27aae09a14aed967ce8b219",
},
{ // SM4-128, with additional input
false,
sm4.NewCipher,
16,
"6f60f0f9d486bc23e1223b934e61c0c78ae9232fa2e9a87c6dacd447c3f10e9e",
"401e3f87762fa8a14ab232ccb8480a2f",
"",
"5e8c10afe142dc9c8caf35411b38730a", // v0
"d72aefa9fd527383ad418f6158627feb", // key0
"350be52552a65a804a106543ebb7dd046cffae104e4e8b2f18936d564d3c1950", // EntropyInputReseed
"7a3688adb1cfb6c03264e2762ece96bfe4daf9558fabf74d7fff203c08b4dd9f", // AdditionalInputReseed
"c00836da0fd780cdc81dabec80e344ce", // v1
"f5f3abdeff30df22f4866d83cd96bc1b", // key1
"67cf4a56d081c53670f257c25557014cd5e8b0e919aa58f23d6861b10b00ea80", // AdditionalInput1
"6ddb205ec76567b31a07ee48437acebc", // v2
"5e23cbe8b97065102ca0d87bfd9ae0da", // key2
"648d4a229198b43f33dd7dd8426650be11c5656adcdf913bb3ee5eb49a2a3892", // AdditionalInput2
"b0ac91f148efbdc3570d7e434aba8d24",
"d1f029bb089613d836ddc6fe1d6fb96f", // v3
"8adfe65e9137b18f060ae91e7a6224c1", // key3
},
}
func TestCtrDRBG(t *testing.T) {
for i, test := range ctrtests {
entropyInput, _ := hex.DecodeString(test.entropyInput)
nonce, _ := hex.DecodeString(test.nonce)
personalizationString, _ := hex.DecodeString(test.personalizationString)
v0, _ := hex.DecodeString(test.v0)
key0, _ := hex.DecodeString(test.key0)
hd, err := NewCtrDrbg(test.cipherProvider, test.keyLen, SECURITY_LEVEL_ONE, test.gm, entropyInput, nonce, personalizationString)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(hd.v[:len(v0)], v0) {
t.Errorf("case %v, not same v0 %s", i+1, hex.EncodeToString(hd.v))
}
if !bytes.Equal(hd.key[:len(key0)], key0) {
t.Errorf("case %v, not same key0 %s", i+1, hex.EncodeToString(hd.key))
}
// Reseed
entropyInputReseed, _ := hex.DecodeString(test.entropyInputReseed)
additionalInputReseed, _ := hex.DecodeString(test.additionalInputReseed)
v1, _ := hex.DecodeString(test.v1)
key1, _ := hex.DecodeString(test.key1)
err = hd.Reseed(entropyInputReseed, additionalInputReseed)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(hd.v, v1) {
t.Errorf("case %v, not same v1 %s", i+1, hex.EncodeToString(hd.v))
}
if !bytes.Equal(hd.key, key1) {
t.Errorf("case %v, not same key1 %s", i+1, hex.EncodeToString(hd.key))
}
// Generate 1
returnbits1, _ := hex.DecodeString(test.returnbits1)
v2, _ := hex.DecodeString(test.v2)
key2, _ := hex.DecodeString(test.key2)
output := make([]byte, len(returnbits1))
additionalInput1, _ := hex.DecodeString(test.additionalInput1)
hd.Generate(output, additionalInput1)
if !bytes.Equal(hd.v, v2) {
t.Errorf("case %v, not same v2 %s", i+1, hex.EncodeToString(hd.v))
}
if !bytes.Equal(hd.key, key2) {
t.Errorf("case %v, not same key2 %s", i+1, hex.EncodeToString(hd.key))
}
// Generate 2
v3, _ := hex.DecodeString(test.v3)
key3, _ := hex.DecodeString(test.key3)
additionalInput2, _ := hex.DecodeString(test.additionalInput2)
hd.Generate(output, additionalInput2)
if !bytes.Equal(hd.v[:len(v0)], v3) {
t.Errorf("case %v, not same v3 %s", i+1, hex.EncodeToString(hd.v))
}
if !bytes.Equal(hd.key, key3) {
t.Errorf("case %v, not same key3 %s", i+1, hex.EncodeToString(hd.key))
}
if !bytes.Equal(returnbits1, output) {
t.Errorf("case %v, not expected return bits %s", i+1, hex.EncodeToString(output))
}
}
}
func TestGmCtrDRBG_Validation(t *testing.T) {
entropyInput := make([]byte, 64)
_, err := NewCtrDrbg(sm4.NewCipher, 16, SECURITY_LEVEL_ONE, true, entropyInput[:16], entropyInput[16:24], nil)
if err == nil {
t.Fatalf("expected error here")
}
_, err = NewCtrDrbg(sm4.NewCipher, 16, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:40], nil)
if err == nil {
t.Fatalf("expected error here")
}
hd, err := NewCtrDrbg(sm4.NewCipher, 16, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:48], nil)
if err != nil {
t.Fatal(err)
}
err = hd.Reseed(entropyInput[:16], nil)
if err == nil {
t.Fatalf("expected error here")
}
}

46
drbg/example_test.go Normal file
View File

@ -0,0 +1,46 @@
package drbg_test
import (
"bytes"
"fmt"
"github.com/emmansun/gmsm/drbg"
)
func ExampleNewGmCtrDrbgPrng() {
prng, err := drbg.NewGmCtrDrbgPrng(nil, 32, drbg.SECURITY_LEVEL_TEST, nil)
if err != nil {
panic(err)
}
c := 10
b := make([]byte, c)
_, err = prng.Read(b)
if err != nil {
fmt.Println("error:", err)
return
}
// The slice should now contain random bytes instead of only zeroes.
fmt.Println(bytes.Equal(b, make([]byte, c)))
// Output:
// false
}
func ExampleNewGmHashDrbgPrng() {
prng, err := drbg.NewGmHashDrbgPrng(nil, 32, drbg.SECURITY_LEVEL_TEST, nil)
if err != nil {
panic(err)
}
c := 10
b := make([]byte, c)
_, err = prng.Read(b)
if err != nil {
fmt.Println("error:", err)
return
}
// The slice should now contain random bytes instead of only zeroes.
fmt.Println(bytes.Equal(b, make([]byte, c)))
// Output:
// false
}

224
drbg/hash_drbg.go Normal file
View File

@ -0,0 +1,224 @@
package drbg
import (
"errors"
"hash"
"time"
"github.com/emmansun/gmsm/internal/byteorder"
"github.com/emmansun/gmsm/sm3"
)
const HASH_DRBG_SEED_SIZE = 55
const HASH_DRBG_MAX_SEED_SIZE = 111
// HashDrbg hash DRBG structure, its instance is NOT goroutine safe!!!
type HashDrbg struct {
BaseDrbg
newHash func() hash.Hash
c []byte
hashSize int
}
// NewHashDrbg create one hash DRBG instance
func NewHashDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, gm bool, entropy, nonce, personalization []byte) (*HashDrbg, error) {
hd := &HashDrbg{}
hd.gm = gm
hd.newHash = newHash
hd.setSecurityLevel(securityLevel)
md := newHash()
hd.hashSize = md.Size()
// here for the min length, we just check <=0 now
if len(entropy) == 0 || (hd.gm && len(entropy) < hd.hashSize) || len(entropy) >= maxBytes {
return nil, errors.New("drbg: invalid entropy length")
}
// here for the min length, we just check <=0 now
if len(nonce) == 0 || (hd.gm && len(nonce) < hd.hashSize/2) || len(nonce) >= maxBytes>>1 {
return nil, errors.New("drbg: invalid nonce length")
}
if len(personalization) >= maxBytes {
return nil, errors.New("drbg: personalization is too long")
}
if hd.hashSize <= sm3.Size {
hd.v = make([]byte, HASH_DRBG_SEED_SIZE)
hd.c = make([]byte, HASH_DRBG_SEED_SIZE)
hd.seedLength = HASH_DRBG_SEED_SIZE
} else {
hd.v = make([]byte, HASH_DRBG_MAX_SEED_SIZE)
hd.c = make([]byte, HASH_DRBG_MAX_SEED_SIZE)
hd.seedLength = HASH_DRBG_MAX_SEED_SIZE
}
// seed_material = entropy_input || instantiation_nonce || personalization_string
seedMaterial := make([]byte, len(entropy)+len(nonce)+len(personalization))
copy(seedMaterial, entropy)
copy(seedMaterial[len(entropy):], nonce)
copy(seedMaterial[len(entropy)+len(nonce):], personalization)
// seed = Hash_df(seed_material, seed_length)
seed := hd.derive(seedMaterial, hd.seedLength)
// V = seed
copy(hd.v, seed)
// C = Hash_df(0x00 || V, seed_length)
temp := make([]byte, hd.seedLength+1)
temp[0] = 0
copy(temp[1:], seed)
seed = hd.derive(temp, hd.seedLength)
copy(hd.c, seed)
hd.reseedCounter = 1
hd.reseedTime = time.Now()
return hd, nil
}
// NewNISTHashDrbg return hash DRBG implementation which follows NIST standard
func NewNISTHashDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HashDrbg, error) {
return NewHashDrbg(newHash, securityLevel, false, entropy, nonce, personalization)
}
// NewGMHashDrbg return hash DRBG implementation which follows GM/T 0105-2021 standard
func NewGMHashDrbg(securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HashDrbg, error) {
return NewHashDrbg(sm3.New, securityLevel, true, entropy, nonce, personalization)
}
// Reseed hash DRBG reseed process. GM/T 0105-2021 has a little different with NIST.
func (hd *HashDrbg) Reseed(entropy, additional []byte) error {
// here for the min length, we just check <=0 now
if len(entropy) == 0 || (hd.gm && len(entropy) < hd.hashSize) || len(entropy) >= maxBytes {
return errors.New("drbg: invalid entropy length")
}
if len(additional) >= maxBytes {
return errors.New("drbg: additional input too long")
}
seedMaterial := make([]byte, len(entropy)+hd.seedLength+len(additional)+1)
seedMaterial[0] = 1
if hd.gm { // seed_material = 0x01 || entropy_input || V || additional_input
copy(seedMaterial[1:], entropy)
copy(seedMaterial[len(entropy)+1:], hd.v)
} else { // seed_material = 0x01 || V || entropy_input || additional_input
copy(seedMaterial[1:], hd.v)
copy(seedMaterial[hd.seedLength+1:], entropy)
}
copy(seedMaterial[len(entropy)+hd.seedLength+1:], additional)
// seed = Hash_df(seed_material, seed_length)
seed := hd.derive(seedMaterial, hd.seedLength)
// V = seed
copy(hd.v, seed)
temp := make([]byte, hd.seedLength+1)
// C = Hash_df(0x01 || V, seed_length)
temp[0] = 0
copy(temp[1:], seed)
seed = hd.derive(temp, hd.seedLength)
copy(hd.c, seed)
hd.reseedCounter = 1
hd.reseedTime = time.Now()
return nil
}
func (hd *HashDrbg) addW(w []byte) {
t := make([]byte, hd.seedLength)
copy(t[hd.seedLength-len(w):], w)
add(t, hd.v, hd.seedLength)
}
func (hd *HashDrbg) addC() {
add(hd.c, hd.v, hd.seedLength)
}
func (hd *HashDrbg) addH() {
md := hd.newHash()
md.Write([]byte{0x03})
md.Write(hd.v)
hd.addW(md.Sum(nil))
}
func (hd *HashDrbg) addReseedCounter() {
t := make([]byte, hd.seedLength)
byteorder.BEPutUint64(t[hd.seedLength-8:], hd.reseedCounter)
add(t, hd.v, hd.seedLength)
}
func (hd *HashDrbg) MaxBytesPerRequest() int {
if hd.gm {
return hd.hashSize
}
return maxBytesPerGenerate
}
// Generate hash DRBG pseudorandom bits process. GM/T 0105-2021 has a little different with NIST.
// GM/T 0105-2021 can only generate no more than hash.Size bytes once.
func (hd *HashDrbg) Generate(b, additional []byte) error {
if hd.NeedReseed() {
return ErrReseedRequired
}
if (hd.gm && len(b) > hd.hashSize) || (!hd.gm && len(b) > maxBytesPerGenerate) {
return errors.New("drbg: too many bytes requested")
}
md := hd.newHash()
m := len(b)
// if len(additional_input) > 0, then
// w = Hash(0x02 || V || additional_input)
if len(additional) > 0 {
md.Write([]byte{0x02})
md.Write(hd.v)
md.Write(additional)
w := md.Sum(nil)
md.Reset()
hd.addW(w)
}
if hd.gm { // leftmost(Hash(V))
md.Write(hd.v)
copy(b, md.Sum(nil))
md.Reset()
} else {
limit := uint64(m+md.Size()-1) / uint64(md.Size())
data := make([]byte, hd.seedLength)
copy(data, hd.v)
for i := range int(limit) {
md.Write(data)
copy(b[i*md.Size():], md.Sum(nil))
addOne(data, hd.seedLength)
md.Reset()
}
}
// V = (V + H + C + reseed_counter) mode 2^seed_length
hd.addH()
hd.addC()
hd.addReseedCounter()
hd.reseedCounter++
return nil
}
// derive Hash_df
func (hd *HashDrbg) derive(seedMaterial []byte, len int) []byte {
md := hd.newHash()
limit := uint64(len+hd.hashSize-1) / uint64(hd.hashSize)
var requireBytes [4]byte
byteorder.BEPutUint32(requireBytes[:], uint32(len<<3))
var ct byte = 1
k := make([]byte, len)
for i := range int(limit) {
// Hash( counter_byte || return_bits || seed_material )
md.Write([]byte{ct})
md.Write(requireBytes[:])
md.Write(seedMaterial)
copy(k[i*md.Size():], md.Sum(nil))
ct++
md.Reset()
}
return k
}

251
drbg/hash_drbg_test.go Normal file
View File

@ -0,0 +1,251 @@
package drbg
import (
"bytes"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"hash"
"testing"
"github.com/emmansun/gmsm/sm3"
)
var tests = []struct {
gm bool
newHash func() hash.Hash
entropyInput string
nonce string
personalizationString string
v0 string
c0 string
entropyInputReseed string
additionalInputReseed string
v1 string
c1 string
additionalInput1 string
v2 string
additionalInput2 string
returnbits1 string
v3 string
}{
{
false,
sha1.New,
"1610b828ccd27de08ceea032a20e9208",
"492cf1709242f6b5",
"",
"9e8301725d5f133b4ab7d329fd2f87ae5f89d96a9dd7e2b98beee1c707b8c3fe412d1125b58bae5dc08a11dac3be4a3147347160fef218",
"e5e12450450efe5fdc777c95b8c23c938fcd592e2d788f12461936e4a16131b1f2d11ce7f0159ee1e635e62f3df8bda4fea077ad5f9d06",
"72d28c908edaf9a4d1e526d8f2ded544",
"",
"745c659f2944829ca6e209c8ca2dddecf9f1861383e34e94007a3a51b8444fd5ae738e7d9c0d5e69aa97ee16c49cfd2432eb32ba5738fa",
"a1fc40009357a024d878818cf6f979a88d4cc5d760b308ae1a5b9f067972e6f7cf92ddb129a8d3c1bb0005bcf3f8871fd65e794f1990b7",
"",
"1658a59fbc9c22c17f5a8b55c1275795873e4beae49657421ad5d95831b736cd7e066c738bcbb343933c411c7c17917593c03a77bed56b",
"",
"56f33d4fdbb9a5b64d26234497e9dcb87798c68d08f7c41199d4bddf97ebbf6cb5550e5d149ff4d5bd0f05f25a6988c17436396227184af84a564335658e2f8572bea333eee2abff22ffa6de3e22aca2",
"b854e5a04ff3c2e657d30ce2b820d13e148b11c245495ff03531785eab2a1dc54d994a5597b15c5b10001f49606c88b4ff0d61acb61820",
},
{
false,
sha1.New,
"d9bab5cedca96f6178d64509a0dfdc5e",
"dad8989414450e01",
"",
"5e07c6b72aaa5afcaab1cc3929239debde7f590886ba5bf558b90345f8518cb87a2bccdefa0c22283538e505efdaf2bd643059fd842106",
"362aafd121de087197466e77b9bf6924841c01bd5fa98d6bc0a75b95d91166ec80e1516a10fff3216a7ad0b0c6e4f4d9708ccd69677134",
"c6bad074c5906786f5e1f32099f5b491",
"3e6bf46f4daa3825d7194e694e7752f7",
"66165aed47c55d963e25aa856553e0a5a590ed06e3cec66254c6a3d8ac8b30da6b334145c466a025b445938d84151bbdbe1509e1cc7189",
"bca1bfd5a1c718d53cd73eb584eedc19d5a3396bf558f659ae673106d0abe1f194e695ca67c2e8ddc8ee95ace21e6b12751faa695ac727",
"04fa2895aa5a6f8c5743343b805e5ea4",
"22b81ac2e98c766b7afce93aea42bcbf7b342672d927bcbc032dd4df7d3712cc0019d750e811a157c71db2340f6d022bd498dbd4dd4669",
"df5dc459dff02aa2f052d721ec607230",
"c48b89f9da3f748245555d5d033b693dd71a4df5690205cefcd720113cc24e098936ff5e77b541535870b339468cdd8d6faf8c56163a700a75b23e599b5aecf16f3baf6d5f2419971f24f446720feabe",
"df59da988b538f40b7d427f06f3198d950d75fdece80b315b19505e64de2f4bd95006d7c6d774e39237115e40aca2d4a88ddec412b67ee",
},
{
false,
sha256.New,
"63363377e41e86468deb0ab4a8ed683f6a134e47e014c700454e81e95358a569",
"808aa38f2a72a62359915a9f8a04ca68",
"",
"32ab605ddc8d5651093b8a59bd9d3adea1249e21a69e2e4a3967515fa03ad41ccf5b126eb9f3b268080c952df88241fe4cc27bbcbbbed5",
"8ea2691d1915ebb4975593ca3fbad0ba137026d901a95950a207c41dc7773e15c1e85f4a5f91002866830bebe5c4ee1785b839323fbb44",
"e62b8a8ee8f141b6980566e3bfe3c04903dad4ac2cdf9f2280010a6739bc83d3",
"",
"59177d93843f0550f33933a51eb488168699ab9c85651536a61f7ec71e8b274a151f17e56becaf531dcfc955f2f1adb6536d51b256d53c",
"897c02699f4254e1f33c94f7bfa85da3826df6c2590ed0815cbced36d77aa3375a1582ffc1c887416afd1ba0f04b6ddff81a2b0e5b844d",
"",
"e2937ffd23815a32e675c89cde5ce5ba0907a25ede73e61c9ec76d67da582c94001fda32b60ec40202a164c6a4d66411cc6b99b1284617",
"",
"04eec63bb231df2c630a1afbe724949d005a587851e1aa795e477347c8b056621c18bddcdd8d99fc5fc2b92053d8cfacfb0bb8831205fad1ddd6c071318a6018f03b73f5ede4d4d071f9de03fd7aea105d9299b8af99aa075bdb4db9aa28c18d174b56ee2a014d098896ff2282c955a81969e069fa8ce007a180183a07dfae17",
"6c0f8266c2c3af14d9b25d949e05435d8b7599213782b6eac6cd90a10d48e1c96088f5dba20241b68cb64bb05028c35e5558ef8a6edca6",
},
{
false,
sha256.New,
"9cfb7ad03be487a3b42be06e9ae44f283c2b1458cec801da2ae6532fcb56cc4c",
"a20765538e8db31295747ec922c13a69",
"",
"8037eb9f243343f8af8c756475ea998f47a487c64dfad9945391004b08cf1a9102d4669492f554b543d820f18a90f453ad53acaf39f0c9",
"ed540b209e044dc2591923883c9a3b1b7c265bc053c40aa91971b09be4d3b3034b05f197a09c6339c7c16de14a20e29ea17bf11cbdb248",
"96bc8014f90ebdf690db0e171b59cc46c75e2e9b8e1dc699c65c03ceb2f4d7dc",
"6fea0894052dab3c44d503950c7c72bd7b87de87cb81d3bb51c32a62f742286d",
"cf9d4dd8a2c4fb507addbe849643acef2bcf6a4403082a026d50371bc7f2ea9d3975790238af78b750ef0334b7e42e0b1e71aeb97c6029",
"e16ed4378e0342deff3003334eae72709c31f5b4004ab9870ee73a6ab4c7eb6f18027c717bf8c94ccc1e06ce5a3afaacb431e2f860f7ed",
"d3467c78563b74c13db7af36c2a964820f2a9b1b167474906508fdac9b2049a6",
"b10c221030c83e2f7a0dc1b7e4f21f5fc8015ff80352e416298fcc88847c8d0ca970964fbaa83f411e07fb6d6ac42b95a2c1abce0fc285",
"5840a11cc9ebf77b963854726a826370ffdb2fc2b3d8479e1df5dcfa3dddd10b",
"71c1154a2a7a3552413970bf698aa02f14f8ea95e861f801f463be27868b1b14b1b4babd9eba5915a6414ab1104c8979b1918f3094925aeab0d07d2037e613b63cbd4f79d9f95c84b47ed9b77230a57515c211f48f4af6f5edb2c308b33905db308cf88f552c8912c49b34e66c026e67b302ca65b187928a1aba9a49edbfe190",
"927af647becb810e793dc4eb33a091d0643355ac039d9e1e4d60a2ac023dca791d46f5e560b237047371aa1d629988772af7b96c0d0a07",
},
{
false,
sha512.New,
"3144e17a10c856129764f58fd8e4231020546996c0bf6cff8e91c24ee09be333",
"b16fcb1cf0c010f31feab733588b8e04",
"",
"3a85ca10eac683d6a9270594d17f33a21dad7b9b259c2a174462a5e0c909a133db84b4ee2bdb0f72cdcef7d62854e535468452285dbe8e46bed3965dc9c66952defa48879493edc01bc07ed4973c115cfdd9947a708465351b78b804652ec7cbe7f6e2a09193fa352ff991d38c94ac",
"74ea437c49126ff361feab5639a8ad318d455c94b3f999ff1606f592c27f8bf0be562c7bffa297de8512ef44b0dfc8db5cb17c9692ac0d80f066961e6426084108089eee4a759d5309ec861668ddeb1c31ceef26edad678b6f36c3ebcb9c936cafcee3d9a96ae6554e22d42888ab07",
"a0b3584c2c8412f618406834404d1eb0ce999ba28966054d7e497e0db608b967",
"",
"b37f9aa39c5a80df56c040402407960ef6f8892d1a688ffc93bad6ebe6af44d55ccd66c1f44eb531e9dac1c9447681d7b27b2b703b490032696b32330b5edd123e5ece7c40efe70a29822ea8e4e454bb72085c6b037a8652ec227f899dd01455db8ee7b6b2e92114f6f9fb678e6332",
"908ad858db2c5d21fa1cd860217bd75ad0ba1df2fd24e303964c01113a0b024a1e53640d5ae339040b4357c1f3c0be2f14607b1385e968183c53ecd9a33ddb04b3ac36dfc1353d8571159a0b31b81b5d3de24b8ae6530c838fa8712ea5d4d58763f2be0ab1989987c56bfd315df521",
"",
"440a72fc7786de0150dd18a045836d69c7b2a720178d73002a06d7fd20ba471f7b20cacf4f31ee35f51e198b383740fb34724a0747e261c800fa0f744bdc842d37199f6acf5f4af041a6600878cf72a7ceaa750fa1c23546f962afe97c055683eaf5131d9f9c882edb93c50adba963",
"",
"efa35dd0362adb7626456b36fac74d3c28d01d926420275a28bea9c9dd7547c15e7931852ac1277076567535239c1f429c7f75cf74c2267deb6a3e596cf326156c796941283b8d583f171c2f6e3323f7555e1b181ffda30507210cb1f589b23cd71880fd44370cacf43375b0db7e336f12b309bfd4f610bb8f20e1a15e253a4fe511a027968df0b105a1d73aff7c7a826d39f640dfb8f522259ed402282e2c2e9d3a498f51725fe4141b06da5598a42ac1e0494e997d566a1a39b676b96a6003a4c5db84f246584ee65af70ff2160278166da16d91c9b8f2deb02751a1088ad6be4e80ef966eb73e66bc87cad87c77c0b34a21ba1da0ba6d16ca5046dc4abda0",
"d4954b5552b33b234af9f10066ff44c4986cc51314b25603c052d90e5ac5496999742edcaa15273a0061714d2bf7ffb32b7000bfdeb10605f36174eb33a48a4cc007c23bb03597b4d8a6373ca7037e8a8ff08f63779da9e61878b1886cb084ba68ceef8ad4e5ba7720acbd3b262822",
},
{
false,
sha512.New,
"c73a7820f0f53e8bbfc3b7b71d994143cf6e98642e9ea6d8df5dccbc43db8720",
"20cc9834b588adcb1bbde64f0d2a34cb",
"",
"852d1b4fdd41cd7e0f597c45c8e4b401a5fecf9229b6072451ca65b5289882c686e7919922ce82de2faac83cd4c4eddfa2cdcf6244a4d2acdd34c0232136409bb50ea24d0c33fcfd1aaf1cc110b5353d32e4e6df59ae25ec124000de62fcfa8bb4cb3f3b72e2da2066ef00cd66d9e9",
"f7b0c9cf2ccf58fd8c8b69daa4cf24a874c95b57a9f5be16aaa71ec30070ac8f222fe21788fec14b8a9ad7ad20912c05a6f94548646779a16c787b135ce8d08c49f7e234cbd2c7733571f5ad6479b5fc50403496581b4861ef8ec848affbd2077ab164fc6bb2dd7b008a650504bfd8",
"12dd2aca8879046d23165c60f8aedc20415783e156d42a94346826aaeb02eacf",
"9b59ff78a34eabe0060c2792ca9b49e9781e6b802badf7dbde27caaed3343706",
"181a302352d9ebf0b669730b2441a9f4c16a4b9d25ebc84ed01c460d293cd3e8b7bff1aca32b0ea8d281df0ef8d1ae09d4cf97690c944f4713adb9ede90763f3ed77081c37c0fc60f8b60b5108cf6276c80db14a82aaef1bf8da03781445cfcc7cdc02b1c7a2740874dd948118f7ef",
"28b638d631f054eba562320e9d151f905863dd6c04d8ba41167bcf3b0236d4e5dde1dc7bf690e61b4a65997bd9c67ff908fe7e2443d01c8eac15b2ea5c80ba89f09aa9b8a81d56124bb71586812827f463de90318727102dbd5e59ca5f1af78ab73844695eee0977b754854e525097",
"dc74a9e480a6ff6f6bce53ab9c7bdde4b13d70fb5196cdd5e3a0555ccf06fe91",
"40d068f984ca40dc5bcba519c156c98519ce29092ac4828fe69815482b73a8ce95a1ce2899bbf4c41ce7788ad2982e3cea3266f4cadc50ae528dc61aa7c521489869e3efc6c82ccefbbab45673e0f59d5654cf910fa146d984a42c5f17fb60340c86d0d07c7e2f2e6df3cffd722a0e",
"8f3f229011209b2f399096afb054bccca6bc46aaee98845838fb1fb78b66f3bd",
"e6c96442582811ec90e587525f36c555e2fd6361a0c5b0284917a4fa6f6e8ace83f11a1fb26cea6692b225ae7c5be286dd27471f323d7a2e4431722bb337b1ba0e648ea2e9f0918b50e9111f2377636ba69b0e1cb5295078d76c549c8656940eb15ca5aded7adc46e6fa4b86948f212fea3f3befdeece8b20e420ca84c760196ddf0b074df0a9f097a5db8f6125800f5fe746a62df1208042f1255b524465a17efcf6a537612968430e2adcff30f7407a51ed7305334384e512e003642cca175636819f021c76a2f44e89e6fe39cf164477910379cd314f735c357f9379de22495276b401c98ffb09a6dc03e484b355a9464511401eeaa05b4556e73b55227f8",
"6986a1cfb6ba95c8012dd7285e6be915723206752f9d3cd0fd13e4832daa7db47383aaa4904cdadf674d1206ac5eafa99de1304fc0b6a1b5e32e34a7f4141e89353878c0d3f6a0ba5b9ed452d61260de9e5acbf8134485b3b9e990f59f34d4d43307e40ad0d0a505efdb24b72f807b",
},
{
true,
sm3.New,
"63363377e41e86468deb0ab4a8ed683f6a134e47e014c700454e81e95358a569",
"808aa38f2a72a62359915a9f8a04ca68",
"",
"7a070cb0c9806fe6a74c0396825642690fc458e76397b75b5977e8a5e693687a703b08c8fbb9e9a600d181c530e889336390818ca2c271",
"218bcd7e3a836cc2e275e660a29fab9c1b3e5596275d8f3141f8c7fb3b285b9edda112e7e85e8492c9b4ed9c1ea466b00cce3be9c10a03",
"e62b8a8ee8f141b6980566e3bfe3c04903dad4ac2cdf9f2280010a6739bc83d3",
"",
"99ec25b65124082695c773d8ef03cc2b31a916956bb582752399c3951c9956d21a73a08091f47401e7133844ea6544361961c7cc4d7e6e",
"c7d8714c59bce8c8b033b99ce3577acd68a3b10151cc0a60c4b2790e56ce47592574d6909fab7fc551d33402f364aaa4d6fcc83989b9c7",
"",
"61c49702aae0f0ef45fb2d75d25b46f89a4cc796bd818d0c7bd0a23a3938e9c81783160d900852f33241399b1a69f7c80bc9865e182676",
"",
"00d98d35a2fab8df23e9e1fb9aad143d62c0759eb79e15c37e8f2bc5064e68da",
"299d084f049dd9b7f62ee712b5b2c1c602f078980f4d9816d8f2baf38765be984b6c493497af30f68a56072404f27e45af419d04eb9e35",
},
{
true,
sm3.New,
"9cfb7ad03be487a3b42be06e9ae44f283c2b1458cec801da2ae6532fcb56cc4c",
"a20765538e8db31295747ec922c13a69",
"",
"997cd31a7032c8643ca56de1d34ff4f930b13192e17c8947bcaf9b9d010cf79805511255c7ea18b41cde77e491ca943861ec29780f3f36", // v0
"4c5b167d27fa9d40cbc45d0d9f3c52504a1cb5aa2f37a3fa812037bd1e458412ecff0641dd5cb2785d0f8044151b42842777211547b457", // c0
"96bc8014f90ebdf690db0e171b59cc46c75e2e9b8e1dc699c65c03ceb2f4d7dc",
"6fea0894052dab3c44d503950c7c72bd7b87de87cb81d3bb51c32a62f742286d",
"e3d804eda66df62f425c41047c5812fca471c8236395c92d4bd834c2e52d606be6ad3da8973df16e8567bcb16e45f2842ace91bf6dfeb3", // v1
"1a1b2fffca26953626e0fa3afd377e14e63c5e81275b39f1436b707efb2c3059e6ced8fdb238a45bf05aae9f2417dbf5c4f89d3772f324", // c1
"d3467c78563b74c13db7af36c2a964820f2a9b1b167474906508fdac9b2049a6",
"fdf334ed70948b65693d3b3f798f91118aae26a48af1045be386984b75695902870479c3c53593d332d195ee7f1bed45fc5069cc4f9948", // v2
"5840a11cc9ebf77b963854726a826370ffdb2fc2b3d8479e1df5dcfa3dddd10b",
"48709db5509a03d6131775fbbfe74fe52611e760d22fde61e274a295f4354d67",
"180e64ed3abb209b901e357a76c70f2670ea8525b24c401d146b70b178e33d8fd10f7680c50bbe1f9773ba664dd14cd25d329c380bf399", // v3
},
}
func TestHashDRBG(t *testing.T) {
for _, test := range tests {
entropyInput, _ := hex.DecodeString(test.entropyInput)
nonce, _ := hex.DecodeString(test.nonce)
personalizationString, _ := hex.DecodeString(test.personalizationString)
v0, _ := hex.DecodeString(test.v0)
c0, _ := hex.DecodeString(test.c0)
hd, err := NewHashDrbg(test.newHash, SECURITY_LEVEL_ONE, test.gm, entropyInput, nonce, personalizationString)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(hd.v[:len(v0)], v0) {
t.Errorf("not same v0 %s", hex.EncodeToString(hd.v[:len(v0)]))
}
if !bytes.Equal(hd.c[:len(c0)], c0) {
t.Errorf("not same c0 %s", hex.EncodeToString(hd.c[:len(c0)]))
}
// Reseed
entropyInputReseed, _ := hex.DecodeString(test.entropyInputReseed)
additionalInputReseed, _ := hex.DecodeString(test.additionalInputReseed)
v1, _ := hex.DecodeString(test.v1)
c1, _ := hex.DecodeString(test.c1)
err = hd.Reseed(entropyInputReseed, additionalInputReseed)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(hd.v[:len(v0)], v1) {
t.Errorf("not same v1 %s", hex.EncodeToString(hd.v[:len(v0)]))
}
if !bytes.Equal(hd.c[:len(c0)], c1) {
t.Errorf("not same c1 %s", hex.EncodeToString(hd.c[:len(c0)]))
}
// Generate 1
returnbits1, _ := hex.DecodeString(test.returnbits1)
v2, _ := hex.DecodeString(test.v2)
output := make([]byte, len(returnbits1))
additionalInput1, _ := hex.DecodeString(test.additionalInput1)
hd.Generate(output, additionalInput1)
if !bytes.Equal(hd.v[:len(v0)], v2) {
t.Errorf("not same v2 %s", hex.EncodeToString(hd.v[:len(v0)]))
}
// Generate 2
v3, _ := hex.DecodeString(test.v3)
additionalInput2, _ := hex.DecodeString(test.additionalInput2)
hd.Generate(output, additionalInput2)
if !bytes.Equal(hd.v[:len(v0)], v3) {
t.Errorf("not same v3 %s", hex.EncodeToString(hd.v[:len(v0)]))
}
if !bytes.Equal(returnbits1, output) {
t.Errorf("not expected return bits %s", hex.EncodeToString(output))
}
}
}
func TestGmHashDRBG_Validation(t *testing.T) {
entropyInput := make([]byte, 64)
_, err := NewHashDrbg(sm3.New, SECURITY_LEVEL_ONE, true, entropyInput[:16], entropyInput[16:24], nil)
if err == nil {
t.Fatalf("expected error here")
}
_, err = NewHashDrbg(sm3.New, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:40], nil)
if err == nil {
t.Fatalf("expected error here")
}
hd, err := NewHashDrbg(sm3.New, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:48], nil)
if err != nil {
t.Fatal(err)
}
err = hd.Reseed(entropyInput[:16], nil)
if err == nil {
t.Fatalf("expected error here")
}
}

155
drbg/hmac_drbg.go Normal file
View File

@ -0,0 +1,155 @@
package drbg
import (
"crypto/hmac"
"errors"
"hash"
"time"
)
// HmacDrbg hmac DRBG structure, its instance is NOT goroutine safe!!!
// The instance should be used in one goroutine only.
// Thera are NO hmac DRBR definition in GM/T 0105-2021 yet.
type HmacDrbg struct {
BaseDrbg
newHash func() hash.Hash
key []byte
hashSize int
}
// NewHmacDrbg create one hmac DRBG instance
func NewHmacDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, gm bool, entropy, nonce, personalization []byte) (*HmacDrbg, error) {
hd := &HmacDrbg{}
hd.gm = gm
hd.newHash = newHash
hd.setSecurityLevel(securityLevel)
md := newHash()
hd.hashSize = md.Size()
// here for the min length, we just check <=0 now
if len(entropy) == 0 || len(entropy) >= maxBytes {
return nil, errors.New("drbg: invalid entropy length")
}
// here for the min length, we just check <=0 now
if len(nonce) == 0 || len(nonce) >= maxBytes>>1 {
return nil, errors.New("drbg: invalid nonce length")
}
if len(personalization) >= maxBytes {
return nil, errors.New("drbg: personalization is too long")
}
// HMAC_DRBG_Instantiate_process
hd.key = make([]byte, hd.hashSize)
hd.v = make([]byte, hd.hashSize)
for i := range hd.hashSize {
hd.key[i] = 0x00
hd.v[i] = 0x01
}
hd.update(entropy, nonce, personalization)
hd.reseedCounter = 1
hd.reseedTime = time.Now()
return hd, nil
}
// NewNISTHmacDrbg return hmac DRBG implementation which follows NIST standard
func NewNISTHmacDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HmacDrbg, error) {
return NewHmacDrbg(newHash, securityLevel, false, entropy, nonce, personalization)
}
// Generate generates pseudo random bytes usging HMAC_DRBG_Generate_process
func (hd *HmacDrbg) Generate(output, additional []byte) error {
// Step 1. If reseed_counter > reseed_interval, then return [ErrReseedRequired] that a reseed is required
if hd.NeedReseed() {
return ErrReseedRequired
}
// Step 2. If additional_input is provided, then do update
if len(additional) > 0 {
hd.update(additional)
}
requestedBytes := len(output)
md := hmac.New(hd.newHash, hd.key)
for ; requestedBytes > 0; requestedBytes -= hd.hashSize {
// 4.1. V = HMAC (Key, V)
md.Reset()
md.Write(hd.v)
hd.v = md.Sum(hd.v[:0])
// 4.2. copy V to output
copy(output, hd.v)
if requestedBytes > hd.hashSize {
output = output[hd.hashSize:]
}
}
// Step 6. (Key, V) = HMAC_DRBG_Update (additional_input, Key, V)
hd.update(additional)
// Step 7. reseed_counter = reseed_counter + 1
hd.reseedCounter++
return nil
}
// Reseed hash DRBG reseed process. GM/T 0105-2021 has a little different with NIST.
// reference to NIST.SP.800-90Ar1.pdf section 10.1.2.4
func (hd *HmacDrbg) Reseed(entropy, additional []byte) error {
// here for the min length, we just check <=0 now
if len(entropy) == 0 || (hd.gm && len(entropy) < hd.hashSize) || len(entropy) >= maxBytes {
return errors.New("drbg: invalid entropy length")
}
if len(additional) >= maxBytes {
return errors.New("drbg: additional input too long")
}
hd.update(entropy, additional)
hd.reseedCounter = 1
hd.reseedTime = time.Now()
return nil
}
func (hd *HmacDrbg) MaxBytesPerRequest() int {
return maxBytesPerGenerate
}
// The HMAC_DRBG_Update function updates the internal state of
// HMAC_DRBG using the provided_data. Note that for this DRBG mechanism, the
// HMAC_DRBG_Update function also serves as a derivation function for the
// instantiate and reseed functions.
func (hd *HmacDrbg) update(byteSlices ...[]byte) error {
// step 1. K = HMAC(K, V || 0x00 || provided_data)
md := hmac.New(hd.newHash, hd.key)
md.Write(hd.v)
md.Write([]byte{0x00})
length := 0
for _, bytes := range byteSlices {
length += len(bytes)
if len(bytes) > 0 {
md.Write(bytes)
}
}
hd.key = md.Sum(hd.key[:0])
// step 2. V = HMAC(K, V)
md = hmac.New(hd.newHash, hd.key)
md.Write(hd.v)
hd.v = md.Sum(hd.v[:0])
// step 3. If provided_data = null, then return
if length == 0 {
return nil
}
// step 4. K = HMAC(K, V || 0x01 || provided_data)
md.Reset()
md.Write(hd.v)
md.Write([]byte{0x01})
for _, bytes := range byteSlices {
if len(bytes) > 0 {
md.Write(bytes)
}
}
hd.key = md.Sum(hd.key[:0])
// step 5. V = HMAC(K, V)
md = hmac.New(hd.newHash, hd.key)
md.Write(hd.v)
hd.v = md.Sum(hd.v[:0])
return nil
}

804
drbg/hmac_drbg_test.go Normal file
View File

@ -0,0 +1,804 @@
package drbg
import (
"bytes"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"hash"
"testing"
)
var hmactests = []struct {
gm bool
newHash func() hash.Hash
entropyInput string
nonce string
personalizationString string
v0 string
k0 string
entropyInputReseed string
additionalInputReseed string
v1 string
k1 string
additionalInput1 string
v2 string
k2 string
returnbits1 string
additionalInput2 string
v3 string
k3 string
}{
{
false,
sha1.New,
"79349bbf7cdda5799557866621c91383",
"1146733abf8c35c8",
"",
"4d9c202854ec825e28c032c0c1d8971f658a2b04",
"900918d4a6f2a3e54f62a6b03bcf372de6f8b2a2",
"c7215b5b96c48e9b338c74e3e99dfedf",
"",
"fa5315383a3e5e8e9591667982984353b7a0a8bf",
"45467ed1cc9435d5a1683cec9d8533864ec58202",
"",
"c0e51987773054629ee998cbab5e77478ba960c7",
"ea1ae579b6b071ffbda9d6fe2346c86a32b60a4c",
"c6a16ab8d420706f0f34ab7fec5adca9d8ca3a133e159ca6ac43c6f8a2be22834a4c0a0affb10d7194f1c1a5cf7322ec1ae0964ed4bf122746e087fdb5b3e91b3493d5bb98faed49e85f130fc8a459b7",
"",
"f26b962d0e43a5587031297607079c387fc111f3",
"2af498a9c9387c8cf02b552084cd3aafd23afd2f",
},
{
false,
sha1.New,
"ee57fc23600fb9029a9ec6c82e7b51e4",
"3e9721e4393ef9ad",
"",
"aaac207d2258bf970c58549e8f6e210ba211107f",
"8aade97aacb843b6256ccfa694514a79d4e37d4c",
"841d276ca9519061d92d7ddfa6628ca3",
"",
"56768fe7ba06c56c2c3ee1dff126b70f0e833304",
"c988036512bed2d33a34dc2394bfe37dfd6ff387",
"",
"1d6ada6bfba009849de2398cb55a6efb1ff6bf13",
"a7069625d1b3c57e515511494660bc0402fb64ed",
"ee26a5c8ef08a1ca8f14154d67c88f5e7ed8219d931b9842ac0039f2145539f2142b44117a998c22f590f6c9b38b465b783ecff13a7750201f7ecf1b8ab393604c73b2389336609af3440cde43298b84",
"",
"962cbd9a0e0d025d319f5c5cfe8bded24fe9a79a",
"c5940ea824e876ce9484448ab5672762e10a78c4",
},
{
false,
sha1.New,
"ebfdad13c8f941d279dbb4de8d7706dd",
"fdaa279f5e4428d6",
"",
"5cabbe2d80eed1ddf1b1e42c1264ba79eba1284c",
"dcdb91176e0ce05e3ae661269284b1b284f6997d",
"f785c5b2f833b69b09b71a57cf5701d4",
"",
"c209a646a0a790d5b7b4e1f1673ae5d056b334f9",
"c5d38ec73619b570dbc9c0f0a18961af10089209",
"",
"a957a52715a8d14d83509e7541224c2e8ada2fff",
"19ac7d4a6f57ab5cc32082f0c724072db630509c",
"66e35f9b8e05a861a0b3d01c66c416d5e8b77d4d21328c625cff9163ffc92e753015aa9d7f36ae3a961681d39f271d0b627787868cec3dedc520ecb303f96a43cec67369117af268a19f5284880cb3be",
"",
"d856adf8f9107ac94f100517407fdeb01e7c6f14",
"97ac5e50aa2519a630283677b71fd5480c84f3df",
},
{
false,
sha1.New,
"7d7052a776fd2fb3d7191f733304ee8b",
"be4a0ceedca80207",
"",
"8bd11c639be35d012b8fa9358b25b8996b100b0d",
"1b64cef03525dd4e7584bcb7c797e0c5542237ab",
"49047e879d610955eed916e4060e00c9",
"fd8bb33aab2f6cdfbc541811861d518d",
"5c754b7134f409d22552a30aa674b1b3a0a590a7",
"162373a8ebda0cf1bdc501cc38ef90b659becf52",
"99afe347540461ddf6abeb491e0715b4",
"c4ecfaadba781a1c10b7756470bbbc1eff813a08",
"2b2af03fbe60d589215434ebded5945d6a0f8782",
"a736343844fc92511391db0addd9064dbee24c8976aa259a9e3b6368aa6de4c9bf3a0effcda9cb0e9dc33652ab58ecb7650ed80467f76a849fb1cfc1ed0a09f7155086064db324b1e124f3fc9e614fcb",
"02f773482dd7ae66f76e381598a64ef0",
"15d2c57b07db598f83f07d67b23c6772c3ccf4b2",
"02658247d79451981931d4bc5d838d42065385bc",
},
{
false,
sha1.New,
"29c62afa3c52208a3fdecb43fa613f15",
"6c9eb59ac3c2d48b",
"",
"ca5a106831ab507cae0fccc9067bfbf0a553f9d0",
"1bd9518f24761b1131275ade489516db2c8724eb",
"bd87be99d184165412314140d4027141",
"433ddaf259d14bcf897630ccaa27338c",
"7060974f64c4c6dd6c2991a7712781b3710e6de2",
"322745157f68853ce481ce599d03dbd115af01cd",
"141146d404f284c2d02b6a10156e3382",
"16b255c1dd94882e34b1a5630dc1dca51bf93474",
"ca6715ddd201caa186e7c6bba1306b15c2b1e92a",
"8c730f0526694d5a9a45dbab057a1975357d65afd3eff303320bd14061f9ad38759102b6c60116f6db7a6e8e7ab94c05500b4d1e357df8e957ac8937b05fb3d080a0f90674d44de1bd6f94d295c4519d",
"edc343dbffe71ab4114ac3639d445b65",
"aaa83705d128b5e8b175da966c3dad1cb73a72ab",
"af019a6ba7dfee072efc9735e5288ac1431c209c",
},
{
false,
sha1.New,
"11c0a7e1472cec70fa8c1ca15759ac5b",
"b1c73c22db39cd7b",
"b24e392cb1f3c18af2cb50feac733e32",
"19a03422ae972aa8b3c6f9f06cd8d67cf32c1bde",
"bdd113dc2a898f2ee086769f85b9d510d10db72b",
"c6ab59ff708a5c1f598e75df060e1981",
"",
"dc831116739734241418a975dcac594eb13c6370",
"62a245070b0c8bf07570be54f1aa02756992e140",
"",
"db1b24a92bbb6d7638ce376f9ec0df515291a196",
"83dd36854e46c3b04e86ea0d8685ab054c924cad",
"070e603cd48d56430a5ab461a751ec2a4a6aa6fb6ee52efe9a41e4611eafdfc957184b47bbb017e484ac34c7de56cd7813feb301b5befce573ad0a254e6cfe35b77c30be6b7cb5e7efa72813c7546ba5",
"",
"d3ab4ccd28b9104be57eac8b6fa293497a1ba273",
"7882dba03b6522f7094f2de9eb7b47b2ebb004cc",
},
{
false,
sha1.New,
"e05141adb678c297eebd8136885b6734",
"5b9c0c54a0ff74d8",
"4814ea71a8e11845716b22085cc65f2b",
"c3a9671b90438f5d8cee8c323cc653d42737eedc",
"efcd5a168654b32131b5fa0d98017ff0787f36a6",
"26e26c9323a3da3af6e5a5a1f351cb54",
"",
"8c65b742f0fee1b4a632fed1f004efb22e2eb591",
"c12d25d75dbdaf325e6306b666836208b13ca6ed",
"",
"f8bb4e888520ff5caa66df0ee1ddc3546e467ebc",
"c0ccd43632a814890fc6a2c98cf57d896f502c66",
"5ef29a2e7e821d529d1928e6bab16fb80d6491a98dd53695473dadead4e5142c146f1e29b101c6b1a57d8315ce34db17040c02572c6455d902303dcfcb2ad3052166de790ce0c94af78a51864efd4b12",
"",
"11058e5edd748bbd315c89ebefb4e3b72d05841e",
"19679a8f39c1888208bef66a13dda0ffd96fb79e",
},
{
false,
sha1.New,
"03e7b41c95818eb0b667bfa8a175a824",
"66a1e417a9b6b92f",
"126dded5eb0bc81be37c10bcd9d5f793",
"9671884e9ddb848ea8dd2908b5deccc69b67e302",
"a354572eb8e7e09758fb4a084be292a7670ee014",
"d17e98c2e50ee0db00d25c3364451e95",
"dc596d188e2343802240bc7f5cc60516",
"cfac259ba4dbb8b30300438cb20f96a2ec588530",
"3ca61b3a111c37639973d655a5097196928ecb31",
"14c8ec10f5bdde6b9e75898d7f9f03d0",
"3d8c62b18f1f9150767a2ef3e6edd918ca4ed183",
"c22f4f421a53fd7f7449e873f6c0e0ca1b6ba74f",
"4739b1bcf87404a2290829bd7a61f0b391a794c71c055c7cc513b28dcb5fdc88645bc9cb490f41fab134c6b33ce9336571762754343961de671b02a47960b4b4e23c5bfb87dcc19b260b3bcb921ae325",
"31aa842afcc1daa94098241a87d6ddfc",
"0904e5dd8a54b62532e2d5eaea04f3d168af632a",
"3654b36c6618fe7a37de46ee21e7546039f96162",
},
{
false,
sha1.New,
"e5a81357b91215dda0a0986a3ff5123f",
"9c1838d7360e674b",
"",
"f6debe6572dd2754a1928efaadb1c4d79aa8603d",
"b79e1aac4cb1e531309518cb4ec6b42993b61238",
"592dd232ac83db36abbacfb8c640dc60",
"",
"acb23f384f6ab63b51355dfc4875d60b68c5d0d4",
"878895412d3bde709daf05406e6aeecf81e37b53",
"",
"2160f1b0ef75fffc2bc81621ea4035234ecf5244",
"1383125bc283e0d9fbd5f957fd57fde07edf8269",
"a4d1843c7af208f770f8b5acf64528866d51e731ed5ebc756e81efe8fb8f9c9af89d52e8e8d1c0141ebebc18b1ca78c78a2f21cb909d5bac3b6ae60c4a2ff4176b14905e4afa3ba9e458216d5720ce83",
"",
"e39a379bfb91f673476c171fcc179e1547c3a033",
"4cc81aa1ca4de9831295d86671594a78f5074b81",
},
{
false,
sha1.New,
"12bfb2bff5781128967e9ce4d429453c",
"5aab2be4e92ec855",
"129126c16d99a684f3cb47e7ffb207ac",
"c4520b5effa4fd7825a846cc49ca3941cd0675d8",
"68a71d4eeaa08771dd960e6fea10046f092649bb",
"fa8b0da2cd5031433d64310ba44d47e4",
"",
"9145bfe03440396ea954f1084e9a0d0047735243",
"52b6c07b6cf17d94a80d1e51fbed0d5ca71a74bc",
"",
"64f6d3aa23e7e8cb86ac115d68bbeef3efffe6e1",
"0c373021c29c578e6d25b0594814f8c9ddb9330b",
"766c4a1670dee63ee3aafb6039e86ec5ca2890531974e70fedb3c0218b08faca07ddfaaff0a77f0ae47762b0e1b31c5fb036dca413fb96f6e0ec6ab7dbcbb558aa5d94f429c38e0fd7b39f12721c9935",
"",
"6fd14126a142d1e5c03f0e5ec37c1a3eafd20e6d",
"c775929a2b39c80b63cf796133b8995ef1548c38",
},
{
false,
sha256.New,
"06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d",
"0e66f71edc43e42a45ad3c6fc6cdc4df",
"",
"81e0d8830ed2d16f9b288a1cb289c5fab3f3c5c28131be7cafedcc7734604d34",
"17dc11c2389f5eeb9d0f6a5148a1ea83ee8a828f4f140ac78272a0da435fa121",
"01920a4e669ed3a85ae8a33b35a74ad7fb2a6bb4cf395ce00334a9c9a5a5d552",
"",
"c246fa97570ba2b9d9e5b453fe4632366f146fbd8491146563eb463c9eafe50c",
"ca43e73325de43c41d7e0a7a3163fb04061b09fcee4c7b8884e969e3bdfdff9a",
"",
"df67d0816d6a8f3b73ba7638ea113bef0e33a1da451272ef1472211fb31c1cd6",
"8be4c7f9f249d5af2c6345a8f07af14be1d7adc2b9892286ffe37760d8aa5a1b",
"76fc79fe9b50beccc991a11b5635783a83536add03c157fb30645e611c2898bb2b1bc215000209208cd506cb28da2a51bdb03826aaf2bd2335d576d519160842e7158ad0949d1a9ec3e66ea1b1a064b005de914eac2e9d4f2d72a8616a80225422918250ff66a41bd2f864a6a38cc5b6499dc43f7f2bd09e1e0f8f5885935124",
"",
"80524881711e89a61e6fe7169581e50fb9ad642f3dff48fba5773352fa04cec3",
"5ed31bc06cc4f3a97f7f34929b0558b0c34de1f4bd1cef456a8364140e2d9f41",
},
{
false,
sha256.New,
"05ac9fc4c62a02e3f90840da5616218c6de5743d66b8e0fbf833759c5928b53d",
"2b89a17904922ed8f017a63044848545",
"",
"eaa29892ee1e46198ea68c07588ac12641fc901e484eda321c2f26a9ff328e3d",
"8d3006bd33b7d8b935a8484b786850f107b731a7efc51521848b875c2214d154",
"2791126b8b52ee1fd9392a0a13e0083bed4186dc649b739607ac70ec8dcecf9b",
"43bac13bae715092cf7eb280a2e10a962faf7233c41412f69bc74a35a584e54c",
"25d3b766cd9f8ad5c45efd7fa01cc08dbce8d0d3792ec2b59bfead7bce39ed01",
"3138df070c49f48b080004df669f386676b4cb92b40de4d021b2a9e4451e5013",
"3f2fed4b68d506ecefa21f3f5bb907beb0f17dbc30f6ffbba5e5861408c53a1e",
"06624fa590e1d63397b13a0e69081274434f793fdfc1e6298a7373834024da46",
"cac850b111de755bb8a5ed1ebc052ed53ab1ff1b9d0fab2946a3728c7e9f43e4",
"02ddff5173da2fcffa10215b030d660d61179e61ecc22609b1151a75f1cbcbb4363c3a89299b4b63aca5e581e73c860491010aa35de3337cc6c09ebec8c91a6287586f3a74d9694b462d2720ea2e11bbd02af33adefb4a16e6b370fa0effd57d607547bdcfbb7831f54de7073ad2a7da987a0016a82fa958779a168674b56524",
"529030df50f410985fde068df82b935ec23d839cb4b269414c0ede6cffea5b68",
"92971e96fc46608d4343821491990915cdb957ae983ab6cdab84fd094bce1380",
"b15ae269570790a8c6a81c5be7aef33f645abb161d218761ff8739cb7997eed8",
},
{
false,
sha256.New,
"fa0ee1fe39c7c390aa94159d0de97564342b591777f3e5f6a4ba2aea342ec840",
"dd0820655cb2ffdb0da9e9310a67c9e5",
"f2e58fe60a3afc59dad37595415ffd318ccf69d67780f6fa0797dc9aa43e144c",
"8ef5e5870a97c084d1755e84fd741309679c35fa9c7d35daf22209ac26428773",
"7f37fd4ce652ffbe367106d3b36e0111653e8cbe85004d92f18576c93586ca94",
"e0629b6d7975ddfa96a399648740e60f1f9557dc58b3d7415f9ba9d4dbb501f6",
"",
"ee34cedfaa282d1d55e0bb001aa5ae42c1f90b56c6b426ad47deccce83786f38",
"fd616afaa26dd2fc3c2e93cf84af86e6d948fa01c617758816d5ea689925b812",
"",
"12a5a939f3f229cb85a1d6fb72ca5e109959726dda4ff9d95c11d7129ad3c1f9",
"d4bbadb25daa6f76c18ad05c07e448f719f0af2f535e2f938e2dcc5dfa5525b7",
"f92d4cf99a535b20222a52a68db04c5af6f5ffc7b66a473a37a256bd8d298f9b4aa4af7e8d181e02367903f93bdb744c6c2f3f3472626b40ce9bd6a70e7b8f93992a16a76fab6b5f162568e08ee6c3e804aefd952ddd3acb791c50f2ad69e9a04028a06a9c01d3a62aca2aaf6efe69ed97a016213a2dd642b4886764072d9cbe",
"",
"53bc9a0420b02b4f6a60aacd8e0320bc440a2385e27887e6ceba60571b27aa47",
"eab97b2cf76bd1817dc5d6826361b51c4dc8776ef643254dae01f83b23c2d5c2",
},
{
false,
sha256.New,
"cdb0d9117cc6dbc9ef9dcb06a97579841d72dc18b2d46a1cb61e314012bdf416",
"d0c0d01d156016d0eb6b7e9c7c3c8da8",
"6f0fb9eab3f9ea7ab0a719bfa879bf0aaed683307fda0c6d73ce018b6e34faaa",
"6c02577c505aed360be7b1cecb61068d8765be1391bacb10f4180d91bd3915db",
"108a7674f3348216c91f5745dd87a919f552fc44373b84ad4b3b843a26b574cb",
"8ec6f7d5a8e2e88f43986f70b86e050d07c84b931bcf18e601c5a3eee3064c82",
"1ab4ca9014fa98a55938316de8ba5a68c629b0741bdd058c4d70c91cda5099b3",
"21a645aeca821899e7e733a10f64565deee5ced3cd5c0356b66c76dc8a906e69",
"e57f901d4bff2909f09467003096edfdb46c89af6bd82e904d11b6753d645c90",
"16e2d0721b58d839a122852abd3bf2c942a31c84d82fca74211871880d7162ff",
"490c0b7786c80f16ad5ee1cc0efd29618968dce14cccebecec8964ea8a41b439",
"648f92d385c3fbf61526deef48ca5ca4dfe4646d82fe8e73bc1705824e181dc9",
"dda04a2ca7b8147af1548f5d086591ca4fd951a345ce52b3cd49d47e84aa31a183e31fbc42a1ff1d95afec7143c8008c97bc2a9c091df0a763848391f68cb4a366ad89857ac725a53b303ddea767be8dc5f605b1b95f6d24c9f06be65a973a089320b3cc42569dcfd4b92b62a993785b0301b3fc452445656fce22664827b88f",
"53686f042a7b087d5d2eca0d2a96de131f275ed7151189f7ca52deaa78b79fb2",
"47390036d5cb308cf9592fdfe95bf19b8ed1a3db88ed8c3b2b2d77540dfb5470",
"db4853ca51700d43c5b6d63eb6cd20ea2dbe3dff512f2dc9531b5b3d9120121c",
},
{
false,
sha256.New,
"ff0cdd555c60464760b289b7bc1f811a41fff72de59083858c020a1053bdc74a",
"7bc099285ad5621993b639c4a94c376b",
"",
"b38a63e3481f97dd59c74511899e1f4cb77b778e3f8815fa6f2094b44d5a0654",
"29bd9df8847368493ce8d0e073aab128a67b41f93eedbeb0026a9692d97dd26d",
"14fc6c9b178db644a8cd7130a4cf051678c8f4fa8f24c27b0a531338a5ce8589",
"",
"548b3fd5d4d80f0fbcc9c97ae9558156867f3d4d484c6b18da5cb16e697cc6ed",
"34aa93c837e97411d0c95983f9b1d758a5068be88b144e64a1fa0bf68f69e8da",
"",
"ae75026c2254d2365d6cf7a163b4d3b2c77ac5f46a4332b5282ba6d8b7b536b3",
"509923309fac70e02cea78879e8b85bac27a6a697d21464626d8a6e2d7ce1fcf",
"2f2620347bddcaa2943685346bbf31c44081f8665f3ddb2b42ae1416a74c4b77fab3fa19aeecc547e76c8cbe6ad1f100a3fc8b2ce2a1ea3a3dd7cfad46c1b27830b940ba18d09e9b7fa902bb760669b1735cc7b7bd39052da7f2626fa87000cffada410019d053386ad808bd3c0cfcf56b91879eb8d3f932ee2d185e54f31b74",
"",
"f57c1fce260aeef586bc35e5f4fc4eb472119527f4904cfe68a82e05b43d5c31",
"7f7d67925b617a068e249b60b04c6febc093a83fad1b88df7cb98bf2f066f669",
},
{
false,
sha256.New,
"d5303207d58bffb97e0772dc848e7e32dfe2f517fcc9b82f256dcbbbe225a543",
"478f5d6ee7101835a177bd002ac75955",
"",
"a1d4aaed8499761fbc5a11242a416d7bffb9cab72ededa9055e43c7acf2a2c8e",
"3e8c47c5b200169ea78a59314b2c994cac510b7f4ffbf4bc3c1a597959fdd38d",
"e2b00122b868747633010cf2e505db7fe89b197f0847508ec385d2180c97b962",
"1c2a88e25d1711c7862a849eb9a217c2a4219031a0d2e0c2c2dfb5f160b2528b",
"0508e475308c870b27b7ed3ea896569bd5481d31e16070047c62615dd96b5256",
"e5cf473b8f30c10c5ba76c74329baef3f96c06b047ae23b0631f2c80ff364cb4",
"282e5c2989d4df5e1ce476bf05057b7560cab5447b15992951db78f7a92767d9",
"bbc4c4a0450848e704729689ff55d135fe6f80132590a0518de4836095397d7b",
"c4e05db3f077be5fb7d2e52f11fd9655f7635d33baafe66859b1bf1f9958dfab",
"623af8a786c2303f1248eda345d3a80df15a6be6cd34973d68c454ea1399390a41835266c27d0d2efc7bab2207022b2adbd8de654937b49bbf620a716fb0c69911c39b2f96ace53d81fd1bc015364dfdb4b226f216a2a129fd0d1a061d74f4aaf6cc8871e015a480e527aad612f40178ad40d4f790b6f81de9b4669b194b799f",
"3a5b9e896338713c7707aa03360a3027f76e2418bdced7d3e8062196e2721887",
"b191e0371078f06d71f458812e28f5f7c57ef8cf2fbfd764ec53a090372dd7ce",
"9af4e6cfc51dc5fca8658e64e515e20aaac94401c70b44bb88d8883a7da670b8",
},
{
false,
sha256.New,
"28ba1a661632efc8ecced5f51b791300fb3b55b05d041708638de4beb757a9e5",
"76828796aff07f55795cb54713c77ed4",
"40933fdcce4159b0955111f844471b0db85b73bdd2b78c468dd39e2a9b29aef2",
"37f4c974532bbf210847f1f05181ec855022c3b8acb0d34cf07e64b979849d27",
"986cf15107e33375fbc9388fe3d75235ce8e6776aeed4d221cbbe3b644ff972e",
"a5f542b04aaa5dbc931e47019feb38962616c57af09b7c1df83f2b860ff76586",
"",
"7efdf833e6dd9f5729d4acbc990fefbb4c30660bc1e84e8ccf06691946dae5e4",
"18a8a6433b6814350293e9806bf70e98644bacc8a7b7b5f71b51ed7d552dd7b2",
"",
"e17005e5a980016e84c3b000cba73dffa728013a7d7e4dbc5dd96443df087703",
"d8b48fa398ac7fc186a84a8f11ac585f482f54c420baa66b5ed1be2d0bafadb7",
"65e5aa47b385f1ea42b231b9fe744253b8598859d7011e525f5a2a1ad32a972a850802c60a2be19be270063a3cfbeaae954f10b122352de6a08ac410e0991653aab271b360fe9191cf5addcccced8c4acfb61457049992988fd7a9acca1f1bca35f1475813694a39988e5fac9f4ac0572286bc462582ad0af78ab3b85ec17a25",
"",
"ad4f354b7c48ff344821d0de7a250e4f26e6772e26d09f187af20ca466d4ba24",
"73d833d2f2ca0d420ae761dcfae629e40891570dbe59e86450d6f53b41446d15",
},
{
false,
sha256.New,
"40f4a4344082039f5452c3fd21aba9393d253c558728346b6954b00f0c64beb1",
"f8e297eedaf4384a12d91e5b3432c69f",
"11716a84a8b4e5717b61f0827cc9e56e21c0acb9b40372f68902576b50c46ba5",
"027ba7ca6c2cd795b794c517826243335452fea4727b2a09253c02b106261c9c",
"f65cf5100d3e62e80d2f836143c4b6b054acc2d563ae4b2ea7b713dcf02adcec",
"07402212d59681934d22d9bde4cb04d69d2fca68e184c526de933669bfa18f78",
"604e8c8e5fd3c9368288451929c9de0e7f537493d7adba56dc400961abebe501",
"c54e1f38a41b642740d7d917fe2116d6bf0eaad51d8ea595ec5254dafba3417d",
"6f25e235bdf69d4a4bcd1fbe857de81f09921571e0092e85d5370910a6aaef64",
"34cecc853e6e379bfd1e13b8eaed00db34602e33760c590e3f75f10ea2e26951",
"1a6bc09b053ca036d9a8ee8e4985172cc59c14bf69f090a4abe52c1d84e17ee9",
"8632c8a9393c4fac921b885d8f9a0057a19a2e63cae7e67610705625d76f0951",
"3ca3ebc8cdd8280c07213c5a5f1e937ba1294c9aa682ca1a3dee63842132b8da641b340861abe7512074f6d1b9745a541ccf19cc1224967a9faa285e21d7572b3e669d9a3647c30d43c27974fbdb461d468149fc1b340d4ee6c640cfe194669d85d4a595bd1b78808e0496d0e2e38a1b9bc1d0e5273fa03cb5f041bfea7f1c9e",
"82b7f37cb3ca1543927659fddb13d09507fe77c941c5d60d451a9103f1b0b5e4",
"d947854c922986cf1ae2238de3dd913b7cc4980b68e7f0cf30fbafce032fc523",
"bc666597b26ad183696cde941daa3b551e8bafd0df774343c9821904e52e2f8f",
},
{
false,
sha256.New,
"6ae80303292391335bf9c9387fbd3bf615756c9c27c3478c87e260cf97d47110",
"01e16247dd4cae6499337d82784ea57f",
"",
"e2f8032e3792b4dd0c3627ec47d174de10ba62f5d9b199de919082bdd8fd13f9",
"87e52aacf4ed425e22d33d74525c9ca07d07784779df5cd6a721de8cce6428bf",
"035702ef4e112b173112c5851d07b279309863740d38d0d0720223e24017bbc0",
"",
"61cd66e5243e1f1016e57157d492d663d912b53d79ab0b592a1f44a5d9a5405b",
"62f41f0b598858cd999cf3e562dfe6fe41b32a7a99a8148eb12dc257bc967459",
"",
"5852153685d511d0bf62977a544c6fc59d877a83fb5639efacc2630ab5feb68b",
"743b37c4f072f87705f9fd8142e0d5012674f7ba13004cc085d3442675f793c0",
"cf4315598fcd6af1315518c4bfbac0540c589635273548a7b507e7d2e685e5947b87ae257e58faf214f2b58ed10c3bd35f75f6c35dd6d441c93bcd42e71720102631b1a6a4ba247c175ed800cfca6e1e839b5aa907604ccfe6f984f6822e001ab02dd6634964f789cb107a977346693f3244c895e840dfa0edf7f14dc61d794f",
"",
"d606304db9bffaeea999ef797238cb680edbf2562e096f77359464bb777b01c8",
"1334aecfff15ed5ae3d02acbd58a72b63cbc6485d1a461398620ce6a0623bf3a",
},
{
false,
sha256.New,
"010935ec2370e1f0fedf365cd4e37666727cc33eb799f38b1cfd226b7037d9b1",
"e09e498a94860ac567ae911bb218f36e",
"",
"e341ac03662f309e62d69216408cd5ad77159238aaa18927485ed39b94d7dc48",
"6cf8613c8c8be636dc49fd8951f7c7aadd48345fd01a6db8bc9754815012db6e",
"d21a3b9a439bb26fa4b4009807c5cafed3ccff19b2b0608a29f0ef6289f27abb",
"204fa3482fe99b6670ec70b7f2558a5ce9caa98113bad174b85a719410010867",
"e4503fa75ff6f9de250c7167a67f3901af2e0698080d8c7325a020437e6ab788",
"9f5ac47eb6d7c6c9dd64b8f90e77d1c5698d5f15db14a93b16db590a61361687",
"4f61b22033e1cc256f5c677e91882914abca6a5a3f716af0ab2c652ff8bce5f8",
"eafdeb36ac2c280af0b3ca5aa8fc89bd35f28be936a226e9838df27257676f67",
"f1e06eb0a70d41b38f9f14ad29391991c7c1d63800ca4958bb704fb43a455646",
"503e08620268aff772e06603679a7509b4bd590787375a4319fd1f7c7ca7261aa1ef336d862096b4cb98ba97c5e96905e410e719fe2a2de1be621c5a537d1596c7e20db9b242523fc926e22e2826bddabdca1c0b8e2fdb32c87044eb6e7760c6634bd9b96d385f98fb0f8a273dc21bb7dbecc29ff69bd691688db2a4b013576c",
"ce1eb61f9af9727844666e283f2ae69eb7c91d098535fbf2ac7b0584ba81560c",
"08d033ceca9b9bb3f196b5ddbf8090fb794ca49d2024cfd2006bde9644132c03",
"54573b125c5e81f4b43d9c83097d1f9f17b97709587b0e27322283d29df8aa37",
},
{
false,
sha256.New,
"633d32e3005f78114723b3ea5ac121ba74aa00c52d939667e30c3351b38549f7",
"37afff504a2d8ac168c68e24d0fe66f6",
"9f1699c99d60b085bc61cb110ef8ab590d82a970021c3c6a5d48021c45de4956",
"f7c520ba361753f1df1c15e95182d4d4e323ab57226702a4f40480d3f5f02154",
"16a8cfadfd0a75b24b3f7ef16c0628c99e0c44117141caad5f6d191006bc9cc9",
"3e3347c547f17f4d0b9f46405a54eedd7e980d06a215ec15e89316ab743b7547",
"",
"2a647361226a2176a700b3c62d7f8c00d52d9ae2d11ea859f7bd009ef379c02b",
"71e8992a9d2d956c40d30e495fac5547b40e108a74e7afb26638e5a5aa411c92",
"",
"b1e011a27e4e68ac1925249aebad9814b8f8f92d4ea63fed97e441a7d49b0631",
"25b7d30f319c23b20d6cf2a25ec6aa79cb153b0bfa7168bb4d242e86d08c98b6",
"6e38e82962d707ce9a6ac383a738a748f975eb785611fad5e3f5a4fe44d7b59a98137a2bcdc35f9ee9a1e21bb17df1665cd1397625a177247e2e329a660140636141560610a368bfd499c2e25be318aa4da9e7a352d115db8282ed8d79ecf9cd820360d3d2d1a58a93e040f5554887ce6c9858bc2bb102249980a858498abcda",
"",
"9dffe821ef5928a8a274999ec13931c69e9db73321712275380ee933365afece",
"9884c09fe1dc5f85a3e3d21c59599bcdbf5139995b97d605dcc56b8a4446723d",
},
{
false,
sha256.New,
"d712e0448c7f07ffc32cb24d4a13980f63a95c676d332f3d96dff8faa867286b",
"eae6e959651245cc5420455b264bddc9",
"82e3cc515480a6d3fefc6687ac488ce04c0cb0361fb87098104355bfef4b41fe",
"7ab58eb84a6c028f8aed46449c6e4286a7b2906e694e87ccd6f2ed1dace0469f",
"5bd94103f2c143502267a5d1d607b58f54f9874b408697036f6d44fc1565ea7b",
"b34a0fdbd1082df4fb3404502cb99a2b564b7a7335e485a907693b8be256dd10",
"e500f6f8af3c4ff61f46f933f80e80e4d08376349511de5a2d3394855e5edf33",
"9f99111aab6e887cd0a94ea2e76c6934440ed13d235bbcb3a41a4606e283fbcb",
"922c584abb9871a16bcc28d967ab3e6055fedafb2fd25c0f504d54c17fe10732",
"87c571b98a05b372cbb53429a37d91295f6f8892813ba23c3c21327f83f9f55d",
"3b9feef739f8cd40ee1cb7ed6c5717e28ce590e38b81c6a6411b06bac60fe466",
"890dfdcbc4bf9d42c6102b147552d4fd89fcd129c8860dbd55fbcc0c2e12aa1a",
"ce50ca00cb699b6dfdf0b997b8a425d5d665150579c01232d51b6b296138fd39da0349c9fe1e1c47cb2589342cc9a9dd9d17671a68a4915be152826c3245d51d87b37275a5cf4be9b4c90bfe752065eb93bb99679b25ace57ac6bbd4c7a30ee489cff74f2d11a38782f05301db7c60c9659f08f237de354ff7a8ee10b8d93460",
"72d1895e1c4c3093452447cdb3519c8dbdcaf90fa0821ab5ced0079c03ab8dd0",
"6d82fd4c23194021e4b477fa3d4ebb502eb49965bed4bd3ff8941c22ae4378f0",
"aa11c583a988e28dc40358af31e6a3eed4326bb5833706417f50a8a93f47f50d",
},
{
false,
sha256.New,
"ea28926cd5df4fefd572c9103d87ffb04f599da95e1e6fecb84f53f73fd00d6c",
"cb40e16655b9a2c71e8e3677b9ea6c6f",
"",
"15415c709cd481e15f0bd111bb9e0b94e325bdce66fc651d48e4e0516d0bd7fa",
"9c7c9fa9df4dfb3fb69341a84596106f36e4a100cba6d4070eedb89f5430c941",
"3d2d1db88b8462787a5576c95fd660734fb681f894e8efc47e3be3bfc3098e40",
"",
"d591e3aa2e49fa8454f3d7702d65399eb0ae7a8c7ee2647037defc23f4087438",
"c31973f18e450f9b91397cec700d7ab843e99a65422a06e3aa16d2bb1b271f81",
"",
"e53be6df73127677e8b13133c5dcf047b0f0586079acc15eb1c0aaae447d25e8",
"bf8de52f6fba271ccf659401ed4f719e9acdfe678e64854de34f4b5ac3db76f2",
"e929c6e749c5175031dcc926bce8d529147b5e940f61d0ba1f02831c80c27a23cd4b5ffb507c7d09a77e4c8427e29010cf1c8021a80ca29504caa350a27d6ca4554fe4d8b0235554f251a59ec6729d802b473083b0bd6ca83f6d945b3d1de2b706bdcc3b50ddef57847fff88a4498586ca6afe65e76c2d97f87ddea66f5563e3",
"",
"5351bdb181f7f4d3055ffec5262423afa6489a18af7ddabeb4a3a568d3b0291e",
"c5aa9123a932d3e3e3bbf8b94cecda12c8ffac76ab37037610dc8d45ca6452c3",
},
{
false,
sha256.New,
"82d87758f16581b2bd8bd4374aba49a59b65cb953f753594240e69575d51b170",
"c12ea8a42dbef64b9b3abbae9222f94a",
"",
"957f42a1588fddd245955c3cdbea7323a3806f87ba2cd1e3c3a67f8bc36d6654",
"f3cff36fa5e85d23d10ace40ff1ad926bc6da4cdb8ab33cb09c32ef2028fafc9",
"f9bcb64209e8f68e6e3f996196ab445dba64568c7e572dcd2378e916449e39f7",
"987d93237e7e52d1ef3941407e8739f7d95991bad92a49ad6a681dcab1644049",
"25e551f9ca83b241de672369e37b430a2fe116c8f5e3eb63ebacc6314eb62316",
"3f6f557538af2c779b04f90a38e951a50741ca0d5ef13ff7864df9e5098683eb",
"8dd4dc1e62114a0c7e52537607ea8313fa4128f486d871a8bb8adbcd9bf46c42",
"64ab49c35fe6dcc4bd5bb3adefa5d7f9e24a1392933f27edc5566d0881acc60d",
"5fcdd5efd3ec9615df7091344b92837acebda1d5d579853ff22522109a8890bd",
"ba00a49886a6c34ebcd649bb93989cabb9c1d11f9c53f721c99ab125a6cf4726a79713c2683ddae6ae7939be465e9a2b95d008af76db42973a6b63a33bc662d99afd9bd4c7aaadc116da5d11db66f2fc27bfd471ff5130b40f81c0da8de5ba09661165371818ea61f936b4fbd511efc2dc5a7d24dd56326a0e10b03f1f94465d",
"e16721a200d3f18abfd154eb0dc2c9b7c245e8a2a644d59c2e888d4de11652de",
"e78d061da89c47e35de40f87980a6212088add1d770fb304ca9777dad23d3c40",
"35d25d84e870645b71b69a58dd2adc4cd6144e7a63549f9fac19d214a7573655",
},
{
false,
sha256.New,
"22d8c62bcddf5da1dbdb093d6b1f663dde337343c56ccfd40acbe3302309eae0",
"2a4b8e66deaac38b70d9ffc20c585da5",
"0a337038f4b4573ff43a4321a586ca777c30301267d82fdf937198ac56c7062c",
"6b2ddf937ea35aeff5985662edf9ba5e74c7226baf08d75154f93bb068ee3f4f",
"68f2b025b5d56fe2557a19195bed188c25f8fbe0899c5d8652e05983e3662136",
"0b6fd179e44f149f062da4f66f829c3c58c4a0a4f75ac2a9e0240d43bec30e44",
"",
"5c2b1bf10f2b5d59717c860ea225f6e80492948510099e45f2a6e3120064125e",
"1bb103384b405f8f8e52a1d60abd5e791ac19a1125452ce2950c28988c48a307",
"",
"17d2c28e23ef6b7132ceaaf41ce180a43a1d9ac451c0b22396f242163cd13b23",
"cb1d57115e74a19602379450f6f4c6fb77ac026899cc1f90789e8fd5b608c507",
"046e19b4d8ab38dd08defdd0d7c30c8c75d5689ca26f2bc994ac7fca4fdbee80677dfbdd851e7722835844dca79dec4a3fa82feb884df7d474bd972e12619bd5d6cb1b951eac47eec2581195b531534ede507af6f7417fca84532be7ef5da6738dbf7aadfcd7cb888862b52ec773cf3fd00e6d4efb3071af9b70a49935a3ba38",
"",
"fa3b5fbc00ad399c78d57d3fab7f3e16fd7d5e98d512164d5ab2476a84ffe0a8",
"7a4b87e1252d2937d1092873b54ac838e80a8aca4c58b16383c6826a6afd5102",
},
{
false,
sha256.New,
"00efb9c7f02719ff5c7030ffa897a308d36c11ce27526340728bcd487c80457b",
"09cebd489d363b5578ddf30534ee6a7f",
"27e38c624a8f934e931e195a0cbcf38e4e8d50108dc318743fb4b61cf78a7d14",
"65ee4461fd700036721800d2a71f5110cc8099fe447d4b68f317b821983a2063",
"ac0e155af29e01caf36f5f36944adf9cef01b18a4a7aa5af8d63cd56a1d03d43",
"4c87234a9bb529aebb7278daa089753bd2b501d30677edb6cc31e38788fe0e21",
"0e4dddbe0034180b59303d527a938a447bad9e4a91787d1072e6f41350ff11e5",
"1de6328fc0c04353018c24e671c0828229d2bdb2faf331a9cb6363a68baf0ad9",
"e21c915e4af5e628b7a45d2953dd61b552f256a215dd604a56067829bd4dfabe",
"cb25fccf929812b9fc66aea93e0cafb064e25b8c2989ae5078648ef529ecb487",
"a3d029a688de1596b7a214af9f547d26e0d03bf3f62a5755e5288923b851c02e",
"41b4ab280425b8e79e25011bcfeef18fbfa57b272100351a742afcabb5be78cf",
"7569ff1ad01a56ab283c1f2357bd519e15c0be84b80cfe8ec6e26cf903aa8a17f52311a2458e48468122ce1f4abff12920f7dffa86c46f06d744d198004bdd0b29b1b0f17712863df82406e2c2a2fb73ea99dc3969c7e52aeaea031e0112fbf8d785426ae7c106d876a900ba54c4e9a1f3656990571c6d1fb56131cd1cdb1e68",
"c1685a422e4a0673cea9948937a8fdaa77777066f501aa17493682a83d931e6a",
"53243974490ced473f3bc498415b40d75b08cd275bc596e5572aa14b9b51e054",
"8d5ed0295e15688a8f9d7556fd452d63c6b0dff43e653b607cc79958cb305921",
},
{
false,
sha512.New384,
"096349506f3a7653d54db7ec1d09e93413edd175b6ddbeb00e56752a520ac8ff",
"fc7983b918acadaa71a67e1624f1b502",
"",
"b3b502977d1a8483d98d92ee3b0d9b484a28aefb015edbfce57154ed7dc66814833825c9ec2677b14f5cd696f5c95982",
"6660ea0017ee93b79f448c81361c601fd02bbd8d3d81af2592ed077855b448708c0e0cee59459684c72822bd455f012a",
"4260a0495fdaba58aae41df82505012d480c8e4f751fd7ebc39f9becd694b2a3",
"",
"b9d842a55279faf4656fd858c2785ae7c4596d03543937bab29761f7ce3adeddbf20a1e0bd27d63bc2fe6f5161d12470",
"d4163efe4c2cda7bf426f7b42130abe16d090342b1195435fa67a9f315e7d7d5899ba5b7a52debfa2378fc12b06fbba0",
"",
"622b6ebac986b1a2d420d685dabf0ea169c2e3b75c42fda106d7963ddac536fababe374c1827a078def62e2ca7dc9628",
"4ac4a9fae8f6798c594278c1f5b017dab870e34f940f9912e5047f6da5be00c67157ffa07e90cae534e8673aa0082cbf",
"f4c7bec0c26cf3892d214549ac6f3d82f34c6966d4295099ee56166e879a70ecae130251facda351e903d877b6c5eab5153ce87ba6c7cf8bcc61cbd14cfbe34cf1ed43678aee69cd87b60e6bcb6ff48ebd44ce9e31982d8fe20aec34fa51d625f845f61056575969bf785c2ffab4dcc754f13de63423e94bad8d5e166d96a62a602d3ee4045df162028b89cac45e6207d9097f2b3ac0ab17729251985f276f1287f5c56cc9ba1a79fbdbb291f3a945fbfdbd63cf13b82ec91f7b1085b33279e3",
"",
"16d64f1dbb1e386f6126ee917f6d1a561c5fa3ae1d427c7a210e521cf5b878538c9d2fed5faf87c7f5d2cea0f1da642c",
"7914529cc8599e510f68c86b4c44004417eae219beddd5e4d6e0595f0c2ebcc9eeda6ca7e009c89439a1013bfef2aca4",
},
{
false,
sha512.New384,
"a0c341ddf73d9404177a5fde32cbe21319c318f35cc9afca9ad41a3b06e13491",
"e843cc6afdf2bcd00ce77ff06ce3d8a5",
"",
"004f625d33624306986abd1e424b2c651abfd42f60e58e24d8f6cc70d329b061868704137eff0ea756d42ce8086bd6ad",
"4cede2db1bbdc9fc3a4ba0951ec3f02e942c11d34fef1d25c32702efcf19b01e5651454c732311bdd91af77ace5c70ee",
"4772c46baf142e569ecd9131d6185af3575bb62a41cb646bdcae8a7a9fe60cc5",
"b83491ec1bd89f3fc84acf1aad6fbeb8ef6ab949f41adc6d0dedc53722c171fe",
"5c11272a6c0e7bf5a7328a2abf3f5a51fc53bcf6c7945a66d97fadfe760c63bc07815731be6582e5396ca0a751b9915c",
"c4f07fcc042077073d630e06eb2823beb05a878239048a78110aacf3b436cb2ed398a587a9cfddcbaa8955cf4f3ab0fc",
"b76cec3d6300ecc4a02e810296c7e70bd9b4e7121fc5e971cbb94337980fddbd",
"b42f1505e9cc3ebb10ab39cfaa1d5eba50e642e568d859e95a53b0f6dc5c3ed568e7c0f9347973a01f944afe279f88b8",
"1dc6a2b09d2cf6f4068e31707c997465b56a7139114ff997b4d32d83a3b90fbd56890a2625afaab0fcdfa05d3470cea8",
"98c01d4527fd131cc327e9632104d9eee10407cd73ab607228d37b9b72ca2c987aa794804d505d072561ccd5016bd4189ac9e3db9187822877dd533347b5d2071818bb7683312e1e8806e9b73b021777f7f878bb7d304ec58ce92e5e36d3d05a7383dc77f3fe6eb84b615f3f290bf8a43c34ef5478a30a6ad616157c9d7dd046aa66b522bcef61c9d19382c32425d38ed3fc049e73035af1e8b97388de22c4dcba0bdc09fd36ab7eb3f67659cbd92b8d7f6d74b56fc8daf17068c65fb016e29f",
"2a25cb0ecf913749ad46b585c76097739a14ca7b59f1f3ce4f79bc8a4afd1378",
"6022695c754ccc20b5a7f8ced36af219d58a1fc2d87162be87eec064a074ddc206b70ad6e569573c1ef89f8cdf27f62b",
"f00007567e5e9f16f998454da61493935d718476a8f423d728f8077435609cba1455531f305dd47e1acc7151b2735949",
},
{
false,
sha512.New384,
"4d95f31b9606a5f6d04dff1d89b50becfd0882e6cf51c1c5d24ad843bc12d977",
"eba4582c39d793a63eadb63f292568c7",
"43bf6f32b3b5f580b54179e4102d063536e7c47681d6de3cfe88fd8ec66e4873",
"3e0ada07e834a8751618a80c5a170d0a2b23fcd11724ba72da8df002ce7c442a5eaa49b899dd671ecebaccd3b5abf837",
"c02f8b20c9946489da8560ffd2198fa722d62d9a22414c9ab7a221eddc3cf7e0d3f323f83286f70fbb4d6b9dbb1d82e6",
"fc4270e6c9aec83186a20819a7d35e7f1155ea108794302d593c53ce9d25422b",
"",
"60a9edaabed8af69bc1cd20cc5ef322f3c66175057e3816b4e7cb56f79963a57375105c688e700dda6ee99293838e187",
"5b7048c6a6266aac485fee29839dd93bdaed1cb59b9405901526fda454c1d004c18e64965622f84ec205f6f44a33175a",
"",
"72c661a45691345b76a9d9c745a6113bc3accc930d255afc15cd68042e270abd2fa2bf86cd573a3cd75bbfe4055add12",
"e3016c5a315d26268a7482290d5408ffe9b41a6c8da4d02e9a23d9c5d7de8c932fe9235432c2f82cdbabf91308606827",
"e991d000b24ebdf838ba11f9849591b0029feff33604bc4d71acd94301f8d045eeb1f81f3a101a297403a35859113c099939638680d481c86067f54762892f82146f61cce7bc2c85d395348f3ea2aba6bb3e59dbcf8e41a81918b6cab304d44ea1e32573cd6936f38cdc11d3c2f96290cc27b0dfa3bbbafa9394acdf2f4435170b428563427c4b02ed25924226edf8d5a5eca4eec4aecf98ef2e6f75caa70bdd84877df2e637b7fad621c6170ca5bd86e21d0bb01cc90fe2e76353a9d5687bea",
"",
"0dd623ca0606fd5082825b31fb59dd130151f912a64e340c23d76f78ec1d77da3a3e196dd18138c83fa19dae60a6dd50",
"bb45802d2d5ea3c759314805a0db4d7ce8bda8ea465bcb058486045c773d17ffe2471b9aa1bd79d867c5f3d4721e8705",
},
{
false,
sha512.New384,
"c4868db5c46fde0a10008838b5be62c349209fded42fab461b01e11723c8242a",
"618faba54acba1e0afd4b27cbd731ed9",
"135132cf2b8a57554bdc13c68e90dc434353e4f65a4d5ca07c3e0a13c62e7265",
"d930565481cdc8f47df5f1a60c2c6b1c9c93d8890192a15f6f3f0b2d6190b4705eea8c1996081b17c0d46bfb84d99f9b",
"d655b88f171cc0ee23c178309a999bdbe5a24e03291326bb22cff71246de2da18a165bac2b1f62f71c2963a3287501d3",
"d30016b5827dc2bfe4034c6654d69775fe98432b19e3da373213d939d391f54a",
"a0bbd02f6aa71a06d1642ca2cc7cdc5e8857e431b176bcf1ecd20f041467bd2d",
"96d9e60925d82c869f4f902eaf70518c2a3a3b354cc3cb220141b856ae28a5451b0287e2f3efffaf3f3394de0d3e2e6c",
"b3e0f0eacd32cdb4396a4249977b716b211d9b5ab55955d12df4d226e18dbdd78fc1b5efecc7dff1c8812a68db36e16a",
"93ee30a9e7a0e244aa91da62f2215c7233bdfc415740d2770780cbbad61b9ba2",
"ba136597b9daa78365422ccf2037bdf871a0e617d250678c0db6dd68b463d02cc2238a5768a33ed36e3ded5ed7674404",
"4df2f0c9aebfb6c382ee30e154cc2090766e72fc5355380bcd5f0fe9576247b729e7b5c973d2614ffa056e37622dacb6",
"2aac4cebed080c68ef0dcff348506eca568180f7370c020deda1a4c9050ce94d4db90fd827165846d6dd6cb2031eec1634b0e7f3e0e89504e34d248e23a8fb31cd32ff39a486946b2940f54c968f96cfc508cd871c84e68458ca7dccabc6dcfb1e9fbef9a47caae14c5239c28686e0fc0942b0c847c9d8d987970c1c5f5f06eaa8385575dacb1e925c0ed85e13edbb9922083f9bbbb79405411ff5dfe70615685df1f1e49867d0b6ed69afe8ac5e76ffab6ff3d71b4dae998faf8c7d5bc6ae4d",
"36d922cacca00ae89db8f0c1cae5a47d2de8e61ae09357ca431c28a07907fce1",
"955b79910f09ed836e1a41d204a9678f2696fce5ba26e6ba366eec4198461d20eee5b77377e6ad67fbe950cf010137ff",
"0fa2e4a250d0e2c55706a7302f58dae496c10548023240bfcdb93f07809896633980cddecf8a39b9efc4766e7673f272",
},
{
false,
sha512.New,
"48c121b18733af15c27e1dd9ba66a9a81a5579cdba0f5b657ec53c2b9e90bbf6",
"bbb7c777428068fad9970891f879b1af",
"",
"aa25644df73d1bd2f9082c64a196ecfc23f4782324b724b1d7f99073d6e47da735fa8f6d4bc7eb08cedf56ebf0b1c0a39cb75e95d589468a64ee6cb15c90349c",
"8191bfa36fa063c30f4d9c0bb54d9be4b831c9eb16f4fd34c56ed8db831cd27003081bd50ef75d578af9abdb5eaf384da45963b84d9c49275682350c4c3415de",
"e0ffefdadb9ccf990504d568bdb4d862cbe17ccce6e22dfcab8b4804fd21421a",
"",
"53d265c9981d347fea85e3ae38567f4c118a5592d984fda24dc44e888f7037063d89d83019525080ee3b20d3ec223243cf45d4ea468ae5234ac2a14970985e0b",
"0f3eb26c2be623fc36330be73ce25ccb9a6195a13324a429b9fd205ccd30122aa521184fd324110bf484d8c80f2a71dedbc949668d023b6f5cdff72f69f3b033",
"",
"d1e27c212508713dcce84e7ce6714864b9bf5c48b5f817495fc10ec11b39e5d43b826a7d44acc0ed90f801901108462b12b631a31b8ae0938da4b678daa3d844",
"05271c404b99bf9f96e57c6e2737f2eaba656878173b1b5e82dc1fe54ebb4450f76b3efa00913371eaba8e94ac5f1c23eb781c83448d49b76f36a9d265fddb68",
"05da6aac7d980da038f65f392841476d37fe70fbd3e369d1f80196e66e54b8fadb1d60e1a0f3d4dc173769d75fc3410549d7a843270a54a068b4fe767d7d9a59604510a875ad1e9731c8afd0fd50b825e2c50d062576175106a9981be37e02ec7c5cd0a69aa0ca65bddaee1b0de532e10cfa1f5bf6a026e47379736a099d6750ab121dbe3622b841baf8bdcbe875c85ba4b586b8b5b57b0fecbec08c12ff2a9453c47c6e32a52103d972c62ab9affb8e728a31fcefbbccc556c0f0a35f4b10ace2d96b906e36cbb72233201e536d3e13b045187b417d2449cad1edd192e061f12d22147b0a176ea8d9c4c35404395b6502ef333a813b6586037479e0fa3c6a23",
"",
"3a9703e8d52c68286e9af1fb2841411f53b785ca1fa01d447b4afcb7fd9a83485d7394bb28558d49d55902b0c282edc417bcb0a9505b74a1ad8f71da14e44640",
"94d65383dbdebd813534f1713f0392431ae12e82d3fb6a50c5890152e53ac0c7c0e53912deb35d925ea9e661b6de7cce6dea139bb6361019b0fc96362739827a",
},
{
false,
sha512.New,
"4686a959e17dfb96c294b09c0f7a60efb386416cfb4c8972bcc55e44a151607a",
"5226543b4c89321bbfb0f11f18ee3462",
"",
"2c727eb88ad430a0a7914ef55b0e3547212b8821fa14775f58e256a45d960a61fd6a66b228845551742a31ae973849762f583fe6cd0a665e4490e25ff783f1e4",
"9d0896a238dd283a933ab4d585d2b10f2e91c855e9b49d9985fc8d47aabe75646436fb3fd53a0fdcd7c172455a51d02231c40211c9a2ff06bbd40c6baec10d4e",
"5ef50daaf29929047870235c17762f5df5d9ab1af656e0e215fcc6fd9fc0d85d",
"d2383c3e528492269e6c3b3aaa2b54fbf48731f5aa52150ce7fc644679a5e7c6",
"97be60b6742e6af6cd7692cb5cf65977b71518d4eee93df68bb7373b57b7163c5a123b9ab74b9e9d797d9e617b250ac0e707e0a7d3173302c712cef46cf1a67d",
"e18cf3770e3ff4ccd50739b9acac479e8a83f121d0107c4ad03b182784208e82a26d6c348c60a1b1ce9790c3767f649ffda451efd14d0ae1eeb771c380bee8c5",
"c841e7a2d9d13bdb8644cd7f5d91d241a369e12dc6c9c2be50d1ed29484bff98",
"17c52eff18f2b07d2e62a58da815ad17b11fe62eec41ac84dc779dab44810957213ba1a6fa2ea9ef6f1503b1e5db724142b6f20f471f3f2584f5c8b250193e33",
"43d4bdc01bfe767a12f7248137db68d5f872451b620119ea539397cf8b219673b1f35547cdf62f62a22a39cd77ce9bd0f052687088d71878217602c6735cc28f",
"b60d8803531b2b8583d17bdf3ac7c01f3c65cf9b069862b2d39b9024b34c172b712db0704acb078a1ab1aec0390dbaee2dec9be7b234e63da481fd469a92c77bc7bb2cfca586855520e0f9e9d47dcb9bdf2a2fdfa9f2b4342ef0ea582616b55477717cfd516d46d6383257743656f7cf8b38402ba795a8c9d35a4aa88bec623313dad6ead689d152b54074f183b2fee556f554db343626cea853718f18d386bc8bebb0c07b3c5e96ceb391ffceece88864dbd3be83a613562c5c417a24807d5f9332974f045e79a9ade36994af6cf9bbeeb71d0025fcb4ad50f121cbc2df7cd12ff5a50cddfd9a4bbc6d942d743c8b8fbebe00eeccea3d14e07ff8454fa715da",
"9054cf9216af66a788d3bf6757b8987e42d4e49b325e728dc645d5e107048245",
"1dba36d15b1a3bb892155c3ce14f62f40c7f06e496240aa9947d4c26b1b6add01b583a124f6e5e6a8c1abd6bca963045611189c9cbcc982ee4862449316f1f76",
"e1bdf89b316cf3030ebb9278fe8ba1d46199459f171b3a225e41137755691dfbd041cc4d00744f095f6933d3ffc2dd3351e7a81c10e41fe8f68f41500b877954",
},
{
false,
sha512.New,
"97aef935ea33717e8e8644bb8c4789f375c48a945ded08771149e828a22dc866",
"82580f51070ba1e991d9803f51fd9a6f",
"212300f93899ff7cb144f20426028b976380a348253bcc3ff42b528cd1972549",
"369c1220d1c4e2fa7093eea955c133259fca33f0611be5b244a37b06a0e4fd5795e93f43cc11fee03a619c99b2956c5759241cf2e00212faf00c5ee6b3ac73ac",
"01a1b73d723b0083929bfe8402817da32bf0e210275a2432a7b2f52b5ff927d40123b686c04c4973c5783f3edddc77558d4b679ceb3a99ce521574cd62b1bab3",
"63cd91c1ebb2caa15f2837df8f35cbb6fe96df2674a136990a5976cbbab63bc1",
"",
"a11c607cbb8772a490e9268120d1c41a67941e0d629396a494ae3ca90dfd45b1ad726e23c9a100478b6c9a50be8ebf72dd1f1aa7d77217edcdad2ac275a1b5af",
"0503fc92a158a6846fcb5e180e7b4c9a46e9c8a1dd55cff8b6d3dec035610e593f14cf6c290168637861fe5c4dee3b9e6d837e779bcbdce2268edaa69aacd653",
"",
"c92961a387245d8aa3afa2b95ed1cddec892aa1fde32ee24951efe1ea5987fe7cf2c10229ecde1c48d62860bfa3fca39890d316ba2da1d3c1c24e2ee91738f3c",
"c42b36968f282b8bd7bc3277ccb9fd23f2fd1f2b3c1d9487583040711d3a21c119d89fbc8e2c3c16c976f1ac8c57a107aa4dbfb1315ececbca8ed0d429f5a128",
"0e8533f64b60c23a2655827037db218c2fe9ce430fa4ed6ed9be349c4bdc6f40018b42f486fa04288b3b0c62a12812e76e08c76062a510cc60841f165869efaceef90805bdde2fd66c36c38a2ac9c3cb86bfd30406569e0afd245102f2ea2d49e4ee5f69187227a3f0edfbc1259cb6564a2d4e829b3fc3b6996e37546f1d8a16fcd8201d1ad28661bbb0012daad55d5403e833d8a0068d216c879bcebc054df0c9cba14dad4863ee1f75b78bc488662cb0c91ca4fdfce7df5916b4e62580902c601be706dcc7903858e6b9920735bdaa635add5c06080d82265345b49037a32fcf0a7c9ea6069e3369f9b4aa45493efd7318da2ae9b4fc300498248afaad8d49",
"",
"bb3e2d10d3cf2158822abd8ba82ed7d773e908d51ae7de16c833cccfe47a3f2b77fe8ebcadbb68900666b8e27d6f7f44e481e61b6ff5c330e7865e30c50bc762",
"a2ab1e3e87adddeba12949f4faa6746b697ba877e1cefb1d7c69c27fc2a45d03f80dd05fa652a329c8e95009cdb5f643561fd94db89a13d70d9a26ea288039b9",
},
{
false,
sha512.New,
"da740cbc36057a8e282ae717fe7dfbb245e9e5d49908a0119c5dbcf0a1f2d5ab",
"46561ff612217ba3ff91baa06d4b5440",
"fc227293523ecb5b1e28c87863626627d958acc558a672b148ce19e2abd2dde4",
"ee0af8405fc2d21b1e28284d18e9100abaa7841e89d92bd8ecc68687c378e667f0ed517ff6eb991088068a2823739f166f0eef1d442a85df094dc7690f0b3246",
"3d40b40ab107cdb5c0719ee03e31cb32f6d237396303c6842edcb6a56e412d6036dd6185eb4542fc4ecb1dc73927091f948527cb42ef1c20304100d496cbcc10",
"1d61d4d8a41c3254b92104fd555adae0569d1835bb52657ec7fbba0fe03579c5",
"b9ed8e35ad018a375b61189c8d365b00507cb1b4510d21cac212356b5bbaa8b2",
"b2b05a95a8b4c2c91309508725ec6304282184d26e9df6a650c0fc413902c2cc7bb1ef9490ec46504d7a4d9f6758778e145368aebab1c63d162f5a23aa6a6060",
"b6fd4b1d54d114ae9145dd6241abaa633844382036977ac558ada8cd345863253df1c13a0638f1605ff86b1e3496ea4e97ac53c486c7a8bd760d7566581bc1ec",
"b7998998eaf9e5d34e64ff7f03de765b31f407899d20535573e670c1b402c26a",
"1f58ce2f986917745fab282551b17b824f332483d76a32c1345877e3a7973ab180d96433245abe920e7a0d08e230c25cdd46cb14e202b1a4346c1e538c797d0d",
"eb5bfa832a8b2c7211043465313e7ca1ac3c414c3e9ed4ccc02e2786777e85aecdab88f4b9a6cd62a1e5b2af87990cce57e34c5d5db38f96509a09acb8c1910a",
"5b70f3e4da95264233efbab155b828d4e231b67cc92757feca407cc9615a660871cb07ad1a2e9a99412feda8ee34dc9c57fa08d3f8225b30d29887d20907d12330fffd14d1697ba0756d37491b0a8814106e46c8677d49d9157109c402ad0c247a2f50cd5d99e538c850b906937a05dbb8888d984bc77f6ca00b0e3bc97b16d6d25814a54aa12143afddd8b2263690565d545f4137e593bb3ca88a37b0aadf79726b95c61906257e6dc47acd5b6b7e4b534243b13c16ad5a0a1163c0099fce43f428cd27c3e6463cf5e9a9621f4b3d0b3d4654316f4707675df39278d5783823049477dcce8c57fdbd576711c91301e9bd6bb0d3e72dc46d480ed8f61fd63811",
"2089d49d63e0c4df58879d0cb1ba998e5b3d1a7786b785e7cf13ca5ea5e33cfd",
"30615b8b8d10f81026274dddd95ddd2da1b50de88c02e286693dee4dd3f8e2d4c605e6fa4d4518630b86f6d1f82f24b661aa7d9e3a720f269d87599ebb8ac12f",
"9e2ef438065edf51cdd7b718a11b1a2ced6e7779140f1e5829edff98b6f61d24e774e027284aa44b942469db9054a056455b05b77ff5c1238c4b8e9e6f51b18e",
},
{
false,
sha512.New512_224,
"f7d44498e0d7cfe749833c7bdf3a16809cb467b22df30f7f",
"b5a7763e69b64ec67eaa3806",
"",
"2904c74438042227d60363614f7fafba0c6713e1af8f9e28b50ce7df",
"99908e0abde34f367fac54655d216a1297e689cd21a14f48b367afb6",
"8268be026354c36a66c492fbdfe701ff1c41cc960b0431d9",
"",
"ec4012d7804cdee678c4ccbd830e070a4dbbd79b8da1f5e637d8f4e8",
"568a44312a03a6e517a0c4fd303f9f527b057be617a6542526e532a2",
"",
"ccb2838b2c04d4ae1620b9c23ec643610cc5b44d8ab7b3b0bd5cf508",
"50fa697921521bbbf3b767cf227ee5e9f48f59cdf150435ad7c4420c",
"3685116cd406fdc0dad3fc66ffbc1404db38897d488acc3046bcb13bb23061837c4af3d744d6cfba9c9ecdc9cbfe7fe3398d8d4927d6a7de519203d0787f7618478c0b27af9564839c81801a9e6e49cf64cfb87027bb78183bba9e2873db327c99b149afe6f1e8e65e5026e822fde377",
"",
"65f82f4ed47fce03578d32dca707ad892d3c7fa024be7037f3aa3c16",
"159c00b2b65ac310007e3d0906906315a023a469088836f1b6549d41",
},
{
false,
sha512.New512_256,
"eb314860cd71525c8a406511e899d4125a8041ce9dcbe3d496866982ac4f8090",
"adf81bd208b66e8560d72f076dd4b8e3",
"683537ae09e0073c39e73be9defa838a6e767b908d84a14645913048ceb6eaf0",
"3ab613508a2ba85b63f7a2a4cfddcba3fe23be87ad4e40fa5254e7742e8489bc",
"89301629bc88954597ab966c4aaaba647e86c0ca9ebcc051bf6322e39e08260c",
"80764cf816353078637ee46b0b657eb9eb67bb307a75fbf81c17ad1b9d2c27c4",
"a1bdabfcd7447bfc69d8038f3e19453b09b9a1771cd847aeb8a0debe9fe262d1",
"3542b0e9893fb4eb5184c5b65c110424037e02f7293cf4b3559bfafff0f01c66",
"9350056d9e5f08286e5fb34b27a74db09ff60a750dedff4a295ce99c18bbce5f",
"8e2fc1be2b64970bb822c5a0eb4c02563997de76a0c6a13ffbcc8e6cde2230fa",
"419ee68fe489cf190c740fee49b93dab9d0e7c0b86203cc2dde9bb54b85c5fec",
"f6116be7581ad7f0815863150437db14a884f8248ccac38534a10e069c8c5400",
"c39f34a610c96d995c2ab7bdfafc511737e8cf031cb13af70ca1fb3413a74893f90ae22591c534ddd82da64c998d4fc6be2a4df5129890a00376d97308c418387ca481a35062479dd9a788be4565a1f4b4cdefac6045da934e69b3b7131c95f8d14352a65b68c9bd6c6f6f5cbfbbd7fc51d02d61da8bac9cc89c44e04978e511",
"a9a1a518d95bbac9329f373f8a65957df4d882fe793765db030b07122ff8d549",
"8851d039d2975c933d743b4ad58b50163cfb09079273924280746182fde68e60",
"f3bc690d6d87ac8066202fe7ad34c8235e5123cca199caf0749a869f45c52643",
},
}
func hexDecode(s string) []byte {
result, _ := hex.DecodeString(s)
return result
}
func TestHmacDRBG(t *testing.T) {
for i, tt := range hmactests {
hd, err := NewHmacDrbg(tt.newHash, SECURITY_LEVEL_ONE, tt.gm, hexDecode(tt.entropyInput), hexDecode(tt.nonce), hexDecode(tt.personalizationString))
if err != nil {
t.Errorf("NewHmacDrbg case %v failed: %v", i, err)
}
if !bytes.Equal(hd.v, hexDecode(tt.v0)) {
t.Errorf("NewHmacDrbg case %v failed: v0 does not match", i)
}
if !bytes.Equal(hd.key, hexDecode(tt.k0)) {
t.Errorf("NewHmacDrbg case %v failed: k0 does not match", i)
}
hd.Reseed(hexDecode(tt.entropyInputReseed), hexDecode(tt.additionalInputReseed))
if !bytes.Equal(hd.v, hexDecode(tt.v1)) {
t.Errorf("Reseed case %v failed: v1 does not match", i)
}
if !bytes.Equal(hd.key, hexDecode(tt.k1)) {
t.Errorf("Reseed case %v failed: k1 does not match", i)
}
output := make([]byte, len(tt.returnbits1)/2)
err = hd.Generate(output, hexDecode(tt.additionalInput1))
if err != nil {
t.Errorf("Generate case %v failed: %v", i, err)
}
if !bytes.Equal(hd.v, hexDecode(tt.v2)) {
t.Errorf("Generate case %v failed: v2 does not match", i)
}
if !bytes.Equal(hd.key, hexDecode(tt.k2)) {
t.Errorf("Generate case %v failed: k2 does not match", i)
}
err = hd.Generate(output, hexDecode(tt.additionalInput2))
if err != nil {
t.Errorf("Generate case %v failed: %v", i, err)
}
if !bytes.Equal(output, hexDecode(tt.returnbits1)) {
t.Errorf("Generate case %v failed: returnbits1 does not match, got %x", i, output)
}
if !bytes.Equal(hd.v, hexDecode(tt.v3)) {
t.Errorf("Generate case %v failed: v3 does not match", i)
}
if !bytes.Equal(hd.key, hexDecode(tt.k3)) {
t.Errorf("Generate case %v failed: k3 does not match", i)
}
}
}

215
ecdh/ecdh.go Normal file
View File

@ -0,0 +1,215 @@
// Package ecdh implements Elliptic Curve Diffie-Hellman / SM2-MQV over
// SM2 curve.
package ecdh
import (
"crypto"
"crypto/subtle"
"errors"
"hash"
"io"
"sync"
"github.com/emmansun/gmsm/sm3"
)
type Curve interface {
// GenerateKey generates a random PrivateKey.
//
// Most applications should use [crypto/rand.Reader] as rand. Note that the
// returned key does not depend deterministically on the bytes read from rand,
// and may change between calls and/or between versions.
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)
// ecdh performs a ECDH exchange and returns the shared secret. It's exposed
// as the PrivateKey.ECDH method.
//
// The private method also allow us to expand the ECDH interface with more
// methods in the future without breaking backwards compatibility.
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)
// sm2za ZA = H256(ENTLA || IDA || a || b || xG || yG || xA || yA).
// Compliance with GB/T 32918.2-2016 5.5
sm2za(md hash.Hash, pub *PublicKey, uid []byte) ([]byte, 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
}
// PublicKey is an ECDH public key, usually a peer's ECDH share sent over the wire.
//
// These keys can be parsed with [smx509.ParsePKIXPublicKey] and encoded
// with [smx509.MarshalPKIXPublicKey]. For SM2 curve, it then needs to
// be converted with [sm2.PublicKeyToECDH] after parsing.
type PublicKey struct {
curve Curve
publicKey []byte
}
// Bytes returns a copy of the encoding of the public key.
func (k *PublicKey) Bytes() []byte {
// Copy the public key to a fixed size buffer that can get allocated on the
// caller's stack after inlining.
var buf [133]byte
return append(buf[:0], k.publicKey...)
}
// Equal returns whether x represents the same public key as k.
//
// Note that there can be equivalent public keys with different encodings which
// would return false from this check but behave the same way as inputs to ECDH.
//
// This check is performed in constant time as long as the key types and their
// curve match.
func (k *PublicKey) Equal(x crypto.PublicKey) bool {
xx, ok := x.(*PublicKey)
if !ok {
return false
}
return k.curve == xx.curve &&
subtle.ConstantTimeCompare(k.publicKey, xx.publicKey) == 1
}
func (k *PublicKey) Curve() Curve {
return k.curve
}
// SM2ZA ZA = H256(ENTLA || IDA || a || b || xG || yG || xA || yA).
// Compliance with GB/T 32918.2-2016 5.5
func (k *PublicKey) SM2ZA(md hash.Hash, uid []byte) ([]byte, error) {
return k.curve.sm2za(md, k, uid)
}
// SM2SharedKey performs SM2 key derivation to generate shared keying data, the uv was generated by [SM2MQV].
func (uv *PublicKey) SM2SharedKey(isResponder bool, kenLen int, sPub, sRemote *PublicKey, uid []byte, remoteUID []byte) ([]byte, error) {
var buffer [128]byte
copy(buffer[:], uv.publicKey[1:])
peerZ, err := sRemote.SM2ZA(sm3.New(), remoteUID)
if err != nil {
return nil, err
}
z, err := sPub.SM2ZA(sm3.New(), uid)
if err != nil {
return nil, err
}
if isResponder {
copy(buffer[64:], peerZ)
copy(buffer[96:], z)
} else {
copy(buffer[64:], z)
copy(buffer[96:], peerZ)
}
return sm3.Kdf(buffer[:], kenLen), nil
}
// PrivateKey is an ECDH private key, usually kept secret.
//
// These keys can be parsed with [smx509.ParsePKCS8PrivateKey] and encoded
// with [smx509.MarshalPKCS8PrivateKey]. For SM2 curve, it then needs to
// be converted with [sm2.PrivateKey.ECDH] after parsing.
type PrivateKey struct {
curve Curve
privateKey []byte
// publicKey is set under publicKeyOnce, to allow loading private keys with
// NewPrivateKey without having to perform a scalar multiplication.
publicKey *PublicKey
publicKeyOnce sync.Once
}
// 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. The result is never the point at infinity.
//
// 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.
func (k *PrivateKey) ECDH(remote *PublicKey) ([]byte, error) {
if k.curve != remote.curve {
return nil, errors.New("ecdh: private key and public key curves do not match")
}
return k.curve.ecdh(k, remote)
}
// SM2MQV performs a SM2 specific style ECMQV exchange and return the shared secret.
func (k *PrivateKey) SM2MQV(eLocal *PrivateKey, sRemote, eRemote *PublicKey) (*PublicKey, error) {
if k.curve != eLocal.curve || k.curve != sRemote.curve || k.curve != eRemote.curve {
return nil, errors.New("ecdh: private key and public key curves do not match")
}
return k.curve.sm2mqv(k, eLocal, sRemote, eRemote)
}
// Bytes returns a copy of the encoding of the private key.
func (k *PrivateKey) Bytes() []byte {
// Copy the private key to a fixed size buffer that can get allocated on the
// caller's stack after inlining.
var buf [66]byte
return append(buf[:0], k.privateKey...)
}
// Equal returns whether x represents the same private key as k.
//
// Note that there can be equivalent private keys with different encodings which
// would return false from this check but behave the same way as inputs to [ECDH].
//
// This check is performed in constant time as long as the key types and their
// curve match.
func (k *PrivateKey) Equal(x crypto.PrivateKey) bool {
xx, ok := x.(*PrivateKey)
if !ok {
return false
}
return k.curve == xx.curve &&
subtle.ConstantTimeCompare(k.privateKey, xx.privateKey) == 1
}
func (k *PrivateKey) Curve() Curve {
return k.curve
}
func (k *PrivateKey) PublicKey() *PublicKey {
k.publicKeyOnce.Do(func() {
k.publicKey = k.curve.privateKeyToPublicKey(k)
})
return k.publicKey
}
// Public implements the implicit interface of all standard library private
// keys. See the docs of [crypto.PrivateKey].
func (k *PrivateKey) Public() crypto.PublicKey {
return k.PublicKey()
}

381
ecdh/ecdh_test.go Normal file
View File

@ -0,0 +1,381 @@
package ecdh_test
import (
"bytes"
"crypto"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"testing"
"github.com/emmansun/gmsm/ecdh"
"golang.org/x/crypto/chacha20"
)
// Check that PublicKey and PrivateKey implement the interfaces documented in
// crypto.PublicKey and crypto.PrivateKey.
var _ interface {
Equal(x crypto.PublicKey) bool
} = &ecdh.PublicKey{}
var _ interface {
Public() crypto.PublicKey
Equal(x crypto.PrivateKey) bool
} = &ecdh.PrivateKey{}
func hexDecode(t *testing.T, s string) []byte {
b, err := hex.DecodeString(s)
if err != nil {
t.Fatal("invalid hex string:", s)
}
return b
}
func TestNewPrivateKey(t *testing.T) {
_, err := ecdh.P256().NewPrivateKey(nil)
if err == nil || err.Error() != "ecdh: invalid private key size" {
t.Errorf("ecdh: invalid private key size")
}
_, err = ecdh.P256().NewPrivateKey([]byte{
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x72, 0x03, 0xdf, 0x6b, 0x21, 0xc6, 0x05, 0x2b,
0x53, 0xbb, 0xf4, 0x09, 0x39, 0xd5, 0x41})
if err == nil || err.Error() != "ecdh: invalid private key size" {
t.Errorf("ecdh: invalid private key size")
}
allzero := make([]byte, 32)
_, err = ecdh.P256().NewPrivateKey(allzero)
if err == nil || err.Error() != "ecdh: invalid private key" {
t.Errorf("expected invalid private key")
}
_, err = ecdh.P256().NewPrivateKey([]byte{
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x72, 0x03, 0xdf, 0x6b, 0x21, 0xc6, 0x05, 0x2b,
0x53, 0xbb, 0xf4, 0x09, 0x39, 0xd5, 0x41, 0x22})
if err == nil || err.Error() != "ecdh: invalid private key" {
t.Errorf("expected invalid private key")
}
}
func TestNewPublicKey(t *testing.T) {
_, err := ecdh.P256().NewPublicKey(nil)
if err == nil || err.Error() != "ecdh: invalid public key" {
t.Errorf("ecdh: invalid public key")
}
keydata := make([]byte, 65)
_, err = ecdh.P256().NewPublicKey(keydata)
if err == nil || err.Error() != "ecdh: invalid public key" {
t.Errorf("ecdh: invalid public key")
}
}
func TestECDH(t *testing.T) {
aliceKey, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
bobKey, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
alicePubKey, err := ecdh.P256().NewPublicKey(aliceKey.PublicKey().Bytes())
if err != nil {
t.Error(err)
}
if !bytes.Equal(aliceKey.PublicKey().Bytes(), alicePubKey.Bytes()) {
t.Error("encoded and decoded public keys are different")
}
if !aliceKey.PublicKey().Equal(alicePubKey) {
t.Error("encoded and decoded public keys are different")
}
alicePrivKey, err := ecdh.P256().NewPrivateKey(aliceKey.Bytes())
if err != nil {
t.Error(err)
}
if !bytes.Equal(aliceKey.Bytes(), alicePrivKey.Bytes()) {
t.Error("encoded and decoded private keys are different")
}
if !aliceKey.Equal(alicePrivKey) {
t.Error("encoded and decoded private keys are different")
}
bobSecret, err := bobKey.ECDH(aliceKey.PublicKey())
if err != nil {
t.Fatal(err)
}
aliceSecret, err := aliceKey.ECDH(bobKey.PublicKey())
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(bobSecret, aliceSecret) {
t.Error("two ECDH computations came out different")
}
}
func TestSM2MQV(t *testing.T) {
aliceSKey, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
aliceEKey, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
bobSKey, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
bobEKey, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
bobSecret, err := bobSKey.SM2MQV(bobEKey, aliceSKey.PublicKey(), aliceEKey.PublicKey())
if err != nil {
t.Fatal(err)
}
aliceSecret, err := aliceSKey.SM2MQV(aliceEKey, bobSKey.PublicKey(), bobEKey.PublicKey())
if err != nil {
t.Fatal(err)
}
if !aliceSecret.Equal(bobSecret) {
t.Error("two SM2MQV computations came out different")
}
}
func TestSM2SharedKey(t *testing.T) {
aliceSKey, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
aliceEKey, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
bobSKey, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
bobEKey, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
bobSecret, err := bobSKey.SM2MQV(bobEKey, aliceSKey.PublicKey(), aliceEKey.PublicKey())
if err != nil {
t.Fatal(err)
}
aliceSecret, err := aliceSKey.SM2MQV(aliceEKey, bobSKey.PublicKey(), bobEKey.PublicKey())
if err != nil {
t.Fatal(err)
}
if !aliceSecret.Equal(bobSecret) {
t.Error("two SM2MQV computations came out different")
}
bobKey, err := bobSecret.SM2SharedKey(true, 48, bobSKey.PublicKey(), aliceSKey.PublicKey(), []byte("Bob"), []byte("Alice"))
if err != nil {
t.Fatal(err)
}
aliceKey, err := aliceSecret.SM2SharedKey(false, 48, aliceSKey.PublicKey(), bobSKey.PublicKey(), []byte("Alice"), []byte("Bob"))
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(bobKey, aliceKey) {
t.Error("two SM2SharedKey computations came out different")
}
}
var vectors = []struct {
LocalStaticPriv, LocalEphemeralPriv string
RemoteStaticPriv, RemoteEphemeralPriv string
SharedSecret, Key string
}{
{
"e04c3fd77408b56a648ad439f673511a2ae248def3bab26bdfc9cdbd0ae9607e",
"6fe0bac5b09d3ab10f724638811c34464790520e4604e71e6cb0e5310623b5b1",
"7a1136f60d2c5531447e5a3093078c2a505abf74f33aefed927ac0a5b27e7dd7",
"d0233bdbb0b8a7bfe1aab66132ef06fc4efaedd5d5000692bc21185242a31f6f",
"046ab5c9709277837cedc515730d04751ef81c71e81e0e52357a98cf41796ab560508da6e858b40c6264f17943037434174284a847f32c4f54104a98af5148d89f",
"1ad809ebc56ddda532020c352e1e60b121ebeb7b4e632db4dd90a362cf844f8bba85140e30984ddb581199bf5a9dda22",
},
{
"cb5ac204b38d0e5c9fc38a467075986754018f7dbb7cbbc5b4c78d56a88a8ad8",
"1681a66c02b67fdadfc53cba9b417b9499d0159435c86bb8760c3a03ae157539",
"4f54b10e0d8e9e2fe5cc79893e37fd0fd990762d1372197ed92dde464b2773ef",
"a2fe43dea141e9acc88226eaba8908ad17e81376c92102cb8186e8fef61a8700",
"04677d055355a1dcc9de4df00d3a80b6daa76bdf54ff7e0a3a6359fcd0c6f1e4b4697fffc41bbbcc3a28ea3aa1c6c380d1e92f142233afa4b430d02ab4cebc43b2",
"7a103ae61a30ed9df573a5febb35a9609cbed5681bcb98a8545351bf7d6824cc4635df5203712ea506e2e3c4ec9b12e7",
},
{
"ee690a34a779ab48227a2f68b062a80f92e26d82835608dd01b7452f1e4fb296",
"2046c6cee085665e9f3abeba41fd38e17a26c08f2f5e8f0e1007afc0bf6a2a5d",
"8ef49ea427b13cc31151e1c96ae8a48cb7919063f2d342560fb7eaaffb93d8fe",
"9baf8d602e43fbae83fedb7368f98c969d378b8a647318f8cafb265296ae37de",
"04f7e9f1447968b284ff43548fcec3752063ea386b48bfabb9baf2f9c1caa05c2fb12c2cca37326ce27e68f8cc6414c2554895519c28da1ca21e61890d0bc525c4",
"b18e78e5072f301399dc1f4baf2956c0ed2d5f52f19abb1705131b0865b079031259ee6c629b4faed528bcfa1c5d2cbc",
},
}
func TestSM2SharedKeyVectors(t *testing.T) {
initiator := []byte("Alice")
responder := []byte("Bob")
kenLen := 48
for i, v := range vectors {
aliceSKey, err := ecdh.P256().NewPrivateKey(hexDecode(t, v.LocalStaticPriv))
if err != nil {
t.Fatal(err)
}
aliceEKey, err := ecdh.P256().NewPrivateKey(hexDecode(t, v.LocalEphemeralPriv))
if err != nil {
t.Fatal(err)
}
bobSKey, err := ecdh.P256().NewPrivateKey(hexDecode(t, v.RemoteStaticPriv))
if err != nil {
t.Fatal(err)
}
bobEKey, err := ecdh.P256().NewPrivateKey(hexDecode(t, v.RemoteEphemeralPriv))
if err != nil {
t.Fatal(err)
}
bobSecret, err := bobSKey.SM2MQV(bobEKey, aliceSKey.PublicKey(), aliceEKey.PublicKey())
if err != nil {
t.Fatal(err)
}
aliceSecret, err := aliceSKey.SM2MQV(aliceEKey, bobSKey.PublicKey(), bobEKey.PublicKey())
if err != nil {
t.Fatal(err)
}
if !aliceSecret.Equal(bobSecret) {
t.Error("two SM2MQV computations came out different")
}
if !bytes.Equal(aliceSecret.Bytes(), hexDecode(t, v.SharedSecret)) {
t.Errorf("%v shared secret is not expected.", i)
}
bobKey, err := bobSecret.SM2SharedKey(true, kenLen, bobSKey.PublicKey(), aliceSKey.PublicKey(), responder, initiator)
if err != nil {
t.Fatal(err)
}
aliceKey, err := aliceSecret.SM2SharedKey(false, kenLen, aliceSKey.PublicKey(), bobSKey.PublicKey(), initiator, responder)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(bobKey, aliceKey) {
t.Error("two SM2SharedKey computations came out different")
}
if !bytes.Equal(bobKey, hexDecode(t, v.Key)) {
t.Errorf("%v keying data is not expected.", i)
}
}
}
type countingReader struct {
r io.Reader
n int
}
func (r *countingReader) Read(p []byte) (int, error) {
n, err := r.r.Read(p)
r.n += n
return n, err
}
func TestGenerateKey(t *testing.T) {
r := &countingReader{r: rand.Reader}
k, err := ecdh.P256().GenerateKey(r)
if err != nil {
t.Fatal(err)
}
// GenerateKey does rejection sampling. If the masking works correctly,
// the probability of a rejection is 1-ord(G)/2^ceil(log2(ord(G))),
// which for all curves is small enough (at most 2^-32, for P-256) that
// a bit flip is more likely to make this test fail than bad luck.
// Account for the extra MaybeReadByte byte, too.
if got, expected := r.n, len(k.Bytes())+1; got > expected {
t.Errorf("expected GenerateKey to consume at most %v bytes, got %v", expected, got)
}
}
func TestString(t *testing.T) {
s := fmt.Sprintf("%s", ecdh.P256())
if s != "sm2p256v1" {
t.Errorf("unexpected Curve string encoding: %q", s)
}
}
func BenchmarkECDH(b *testing.B) {
benchmarkAllCurves(b, func(b *testing.B, curve ecdh.Curve) {
c, err := chacha20.NewUnauthenticatedCipher(make([]byte, 32), make([]byte, 12))
if err != nil {
b.Fatal(err)
}
rand := cipher.StreamReader{
S: c, R: zeroReader,
}
peerKey, err := curve.GenerateKey(rand)
if err != nil {
b.Fatal(err)
}
peerShare := peerKey.PublicKey().Bytes()
b.ResetTimer()
b.ReportAllocs()
var allocationsSink byte
for i := 0; i < b.N; i++ {
key, err := curve.GenerateKey(rand)
if err != nil {
b.Fatal(err)
}
share := key.PublicKey().Bytes()
peerPubKey, err := curve.NewPublicKey(peerShare)
if err != nil {
b.Fatal(err)
}
secret, err := key.ECDH(peerPubKey)
if err != nil {
b.Fatal(err)
}
allocationsSink ^= secret[0] ^ share[0]
}
})
}
func benchmarkAllCurves(b *testing.B, f func(b *testing.B, curve ecdh.Curve)) {
b.Run("SM2P256", func(b *testing.B) { f(b, ecdh.P256()) })
}
type zr struct{}
// Read replaces the contents of dst with zeros. It is safe for concurrent use.
func (zr) Read(dst []byte) (n int, err error) {
clear(dst)
return len(dst), nil
}
var zeroReader = zr{}

246
ecdh/sm2ec.go Normal file
View File

@ -0,0 +1,246 @@
package ecdh
import (
"encoding/binary"
"errors"
"hash"
"io"
"math/bits"
"github.com/emmansun/gmsm/internal/randutil"
sm2ec "github.com/emmansun/gmsm/internal/sm2ec"
"github.com/emmansun/gmsm/internal/subtle"
)
type sm2Curve struct {
name string
newPoint func() *sm2ec.SM2P256Point
scalarOrderMinus1 []byte
constantA []byte
constantB []byte
generator []byte
}
func (c *sm2Curve) String() string {
return c.name
}
func (c *sm2Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
key := make([]byte, len(c.scalarOrderMinus1))
randutil.MaybeReadByte(rand)
for {
if _, err := io.ReadFull(rand, key); err != nil {
return nil, err
}
// In tests, rand will return all zeros and NewPrivateKey will reject
// the zero key as it generates the identity as a public key. This also
// makes this function consistent with crypto/elliptic.GenerateKey.
key[1] ^= 0x42
k, err := c.NewPrivateKey(key)
if err == errInvalidPrivateKey {
continue
}
return k, err
}
}
func (c *sm2Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
if len(key) != len(c.scalarOrderMinus1) {
return nil, errors.New("ecdh: invalid private key size")
}
if subtle.ConstantTimeAllZero(key) == 1 || !isLess(key, c.scalarOrderMinus1) {
return nil, errInvalidPrivateKey
}
return &PrivateKey{
curve: c,
privateKey: append([]byte{}, key...),
}, nil
}
func (c *sm2Curve) privateKeyToPublicKey(key *PrivateKey) *PublicKey {
if key.curve != c {
panic("ecdh: internal error: converting the wrong key type")
}
p, err := c.newPoint().ScalarBaseMult(key.privateKey)
if err != nil {
// This is unreachable because the only error condition of
// ScalarBaseMult is if the input is not the right size.
panic("ecdh: internal error: sm2ec ScalarBaseMult failed for a fixed-size input")
}
publicKey := p.Bytes()
if len(publicKey) == 1 {
// The encoding of the identity is a single 0x00 byte. This is
// unreachable because the only scalar that generates the identity is
// zero, which is rejected by NewPrivateKey.
panic("ecdh: internal error: sm2ec ScalarBaseMult returned the identity")
}
return &PublicKey{
curve: key.curve,
publicKey: publicKey,
}
}
func (c *sm2Curve) NewPublicKey(key []byte) (*PublicKey, error) {
// Reject the point at infinity and compressed encodings.
if len(key) == 0 || key[0] != 4 {
return nil, errors.New("ecdh: invalid public key")
}
// SetBytes also checks that the point is on the curve.
if _, err := c.newPoint().SetBytes(key); err != nil {
return nil, err
}
return &PublicKey{
curve: c,
publicKey: append([]byte{}, key...),
}, nil
}
func (c *sm2Curve) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) {
p, err := c.newPoint().SetBytes(remote.publicKey)
if err != nil {
return nil, err
}
if _, err := p.ScalarMult(p, local.privateKey); err != nil {
return nil, err
}
// BytesX will return an error if p is the point at infinity.
return p.BytesX()
}
func (c *sm2Curve) sm2avf(secret *PublicKey) []byte {
bytes := secret.publicKey[1:33]
var result [32]byte
copy(result[16:], bytes[16:])
result[16] = (result[16] & 0x7f) | 0x80
return result[:]
}
func (c *sm2Curve) sm2mqv(sLocal, eLocal *PrivateKey, sRemote, eRemote *PublicKey) (*PublicKey, error) {
// implicitSig: (sLocal + avf(eLocal.Pub) * ePriv) mod N
x2 := c.sm2avf(eLocal.PublicKey())
t, err := sm2ec.ImplicitSig(sLocal.privateKey, eLocal.privateKey, x2)
if err != nil {
return nil, err
}
// new base point: peerPub + [x1](peerSecret)
x1 := c.sm2avf(eRemote)
p2, err := c.newPoint().SetBytes(eRemote.publicKey)
if err != nil {
return nil, err
}
if _, err := p2.ScalarMult(p2, x1); err != nil {
return nil, err
}
p1, err := c.newPoint().SetBytes(sRemote.publicKey)
if err != nil {
return nil, err
}
p2.Add(p1, p2)
if _, err := p2.ScalarMult(p2, t); err != nil {
return nil, err
}
return c.NewPublicKey(p2.Bytes())
}
var defaultUID = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}
// CalculateZA ZA = H256(ENTLA || IDA || a || b || xG || yG || xA || yA).
// Compliance with GB/T 32918.2-2016 5.5
func (c *sm2Curve) sm2za(md hash.Hash, pub *PublicKey, uid []byte) ([]byte, error) {
if len(uid) == 0 {
uid = defaultUID
}
uidLen := len(uid)
if uidLen >= 0x2000 {
return nil, errors.New("ecdh: the uid is too long")
}
entla := uint16(uidLen) << 3
md.Write([]byte{byte(entla >> 8), byte(entla)})
if uidLen > 0 {
md.Write(uid)
}
md.Write(c.constantA)
md.Write(c.constantB)
md.Write(c.generator)
md.Write(pub.publicKey[1:])
return md.Sum(nil), nil
}
// P256 returns a [Curve] which implements SM2, also known as sm2p256v1
//
// Multiple invocations of this function will return the same value, so it can
// be used for equality checks and switch statements.
func P256() Curve { return sm2P256 }
var sm2P256 = &sm2Curve{
name: "sm2p256v1",
newPoint: sm2ec.NewSM2P256Point,
scalarOrderMinus1: sm2P256OrderMinus1,
generator: sm2Generator,
constantA: sm2ConstantA,
constantB: sm2ConstantB,
}
var sm2P256OrderMinus1 = []byte{
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x72, 0x03, 0xdf, 0x6b, 0x21, 0xc6, 0x05, 0x2b,
0x53, 0xbb, 0xf4, 0x09, 0x39, 0xd5, 0x41, 0x22}
var sm2Generator = []byte{
0x32, 0xc4, 0xae, 0x2c, 0x1f, 0x19, 0x81, 0x19,
0x5f, 0x99, 0x4, 0x46, 0x6a, 0x39, 0xc9, 0x94,
0x8f, 0xe3, 0xb, 0xbf, 0xf2, 0x66, 0xb, 0xe1,
0x71, 0x5a, 0x45, 0x89, 0x33, 0x4c, 0x74, 0xc7,
0xbc, 0x37, 0x36, 0xa2, 0xf4, 0xf6, 0x77, 0x9c,
0x59, 0xbd, 0xce, 0xe3, 0x6b, 0x69, 0x21, 0x53,
0xd0, 0xa9, 0x87, 0x7c, 0xc6, 0x2a, 0x47, 0x40,
0x2, 0xdf, 0x32, 0xe5, 0x21, 0x39, 0xf0, 0xa0}
var sm2ConstantA = []byte{
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc}
var sm2ConstantB = []byte{
0x28, 0xe9, 0xfa, 0x9e, 0x9d, 0x9f, 0x5e, 0x34,
0x4d, 0x5a, 0x9e, 0x4b, 0xcf, 0x65, 0x09, 0xa7,
0xf3, 0x97, 0x89, 0xf5, 0x15, 0xab, 0x8f, 0x92,
0xdd, 0xbc, 0xbd, 0x41, 0x4d, 0x94, 0x0e, 0x93}
// isLess returns whether a < b, where a and b are big-endian buffers of the
// same length and shorter than 72 bytes.
func isLess(a, b []byte) bool {
if len(a) != len(b) {
panic("ecdh: internal error: mismatched isLess inputs")
}
// Copy the values into a fixed-size preallocated little-endian buffer.
// 72 bytes is enough for every scalar in this package, and having a fixed
// size lets us avoid heap allocations.
if len(a) > 72 {
panic("ecdh: internal error: isLess input too large")
}
bufA, bufB := make([]byte, 72), make([]byte, 72)
for i := range a {
bufA[i], bufB[i] = a[len(a)-i-1], b[len(b)-i-1]
}
// Perform a subtraction with borrow.
var borrow uint64
for i := 0; i < len(bufA); i += 8 {
limbA, limbB := binary.LittleEndian.Uint64(bufA[i:]), binary.LittleEndian.Uint64(bufB[i:])
_, borrow = bits.Sub64(limbA, limbB, borrow)
}
// If there is a borrow at the end of the operation, then a < b.
return borrow == 1
}
var errInvalidPrivateKey = errors.New("ecdh: invalid private key")

9
go.mod
View File

@ -1,8 +1,7 @@
module github.com/emmansun/gmsm
go 1.15
go 1.23.0
require (
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
golang.org/x/sys v0.0.0-20220209214540-3681064d5158
)
require golang.org/x/crypto v0.39.0
require golang.org/x/sys v0.33.0 // indirect

19
go.sum
View File

@ -1,15 +1,4 @@
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI=
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=

View File

@ -0,0 +1,42 @@
package alias
import "testing"
var a, b [100]byte
var aliasingTests = []struct {
x, y []byte
anyOverlap, inexactOverlap bool
}{
{a[:], b[:], false, false},
{a[:], b[:0], false, false},
{a[:], b[:50], false, false},
{a[40:50], a[50:60], false, false},
{a[40:50], a[60:70], false, false},
{a[:51], a[50:], true, true},
{a[:], a[:], true, false},
{a[:50], a[:60], true, false},
{a[:], nil, false, false},
{nil, nil, false, false},
{a[:], a[:0], false, false},
{a[:10], a[:10:20], true, false},
{a[:10], a[5:10:20], true, true},
}
func testAliasing(t *testing.T, i int, x, y []byte, anyOverlap, inexactOverlap bool) {
any := AnyOverlap(x, y)
if any != anyOverlap {
t.Errorf("%d: wrong AnyOverlap result, expected %v, got %v", i, anyOverlap, any)
}
inexact := InexactOverlap(x, y)
if inexact != inexactOverlap {
t.Errorf("%d: wrong InexactOverlap result, expected %v, got %v", i, inexactOverlap, any)
}
}
func TestAliasing(t *testing.T) {
for i, tt := range aliasingTests {
testAliasing(t, i, tt.x, tt.y, tt.anyOverlap, tt.inexactOverlap)
testAliasing(t, i, tt.y, tt.x, tt.anyOverlap, tt.inexactOverlap)
}
}

View File

@ -1,4 +1,4 @@
package subtle
package alias
import "unsafe"

1196
internal/bigmod/nat.go Normal file

File diff suppressed because it is too large Load Diff

52
internal/bigmod/nat_386.s Normal file
View File

@ -0,0 +1,52 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !purego
#include "textflag.h"
// func addMulVVW256(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW256(SB), $0-16
MOVL $8, BX
JMP addMulVVWy(SB)
// func addMulVVW1024(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1024(SB), $0-16
MOVL $32, BX
JMP addMulVVWy(SB)
// func addMulVVW1536(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1536(SB), $0-16
MOVL $48, BX
JMP addMulVVWy(SB)
// func addMulVVW2048(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW2048(SB), $0-16
MOVL $64, BX
JMP addMulVVWy(SB)
TEXT addMulVVWy(SB), NOFRAME|NOSPLIT, $0
MOVL z+0(FP), DI
MOVL x+4(FP), SI
MOVL y+8(FP), BP
LEAL (DI)(BX*4), DI
LEAL (SI)(BX*4), SI
NEGL BX // i = -n
MOVL $0, CX // c = 0
JMP E6
L6: MOVL (SI)(BX*4), AX
MULL BP
ADDL CX, AX
ADCL $0, DX
ADDL AX, (DI)(BX*4)
ADCL $0, DX
MOVL DX, CX
ADDL $1, BX // i++
E6: CMPL BX, $0 // i < 0
JL L6
MOVL CX, c+12(FP)
RET

1319
internal/bigmod/nat_amd64.s Normal file

File diff suppressed because it is too large Load Diff

52
internal/bigmod/nat_arm.s Normal file
View File

@ -0,0 +1,52 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !purego
#include "textflag.h"
// func addMulVVW256(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW256(SB), $0-16
MOVW $8, R5
JMP addMulVVWy(SB)
// func addMulVVW1024(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1024(SB), $0-16
MOVW $32, R5
JMP addMulVVWy(SB)
// func addMulVVW1536(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1536(SB), $0-16
MOVW $48, R5
JMP addMulVVWy(SB)
// func addMulVVW2048(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW2048(SB), $0-16
MOVW $64, R5
JMP addMulVVWy(SB)
TEXT addMulVVWy(SB), NOFRAME|NOSPLIT, $0
MOVW $0, R0
MOVW z+0(FP), R1
MOVW x+4(FP), R2
MOVW y+8(FP), R3
ADD R5<<2, R1, R5
MOVW $0, R4
B E9
L9: MOVW.P 4(R2), R6
MULLU R6, R3, (R7, R6)
ADD.S R4, R6
ADC R0, R7
MOVW 0(R1), R4
ADD.S R4, R6
ADC R0, R7
MOVW.P R6, 4(R1)
MOVW R7, R4
E9: TEQ R1, R5
BNE L9
MOVW R4, c+12(FP)
RET

View File

@ -0,0 +1,74 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !purego
#include "textflag.h"
// func addMulVVW256(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW256(SB), $0-32
MOVD $4, R0
JMP addMulVVWy(SB)
// func addMulVVW1024(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1024(SB), $0-32
MOVD $16, R0
JMP addMulVVWy(SB)
// func addMulVVW1536(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1536(SB), $0-32
MOVD $24, R0
JMP addMulVVWy(SB)
// func addMulVVW2048(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW2048(SB), $0-32
MOVD $32, R0
JMP addMulVVWy(SB)
TEXT addMulVVWy(SB), NOFRAME|NOSPLIT, $0
MOVD z+0(FP), R1
MOVD x+8(FP), R2
MOVD y+16(FP), R3
MOVD $0, R4
// The main loop of this code operates on a block of 4 words every iteration
// performing [R4:R12:R11:R10:R9] = R4 + R3 * [R8:R7:R6:R5] + [R12:R11:R10:R9]
// where R4 is carried from the previous iteration, R8:R7:R6:R5 hold the next
// 4 words of x, R3 is y and R12:R11:R10:R9 are part of the result z.
loop:
CBZ R0, done
LDP.P 16(R2), (R5, R6)
LDP.P 16(R2), (R7, R8)
LDP (R1), (R9, R10)
ADDS R4, R9
MUL R6, R3, R14
ADCS R14, R10
MUL R7, R3, R15
LDP 16(R1), (R11, R12)
ADCS R15, R11
MUL R8, R3, R16
ADCS R16, R12
UMULH R8, R3, R20
ADC $0, R20
MUL R5, R3, R13
ADDS R13, R9
UMULH R5, R3, R17
ADCS R17, R10
UMULH R6, R3, R21
STP.P (R9, R10), 16(R1)
ADCS R21, R11
UMULH R7, R3, R19
ADCS R19, R12
STP.P (R11, R12), 16(R1)
ADC $0, R20, R4
SUB $4, R0
B loop
done:
MOVD R4, c+24(FP)
RET

View File

@ -0,0 +1,31 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !purego && (386 || amd64 || arm || arm64 || ppc64 || ppc64le || riscv64 || s390x)
package bigmod
import "github.com/emmansun/gmsm/internal/deps/cpu"
// amd64 assembly uses ADCX/ADOX/MULX if ADX is available to run two carry
// chains in the flags in parallel across the whole operation, and aggressively
// unrolls loops. arm64 processes four words at a time.
//
// It's unclear why the assembly for all other architectures, as well as for
// amd64 without ADX, perform better than the compiler output.
// TODO(filippo): file cmd/compile performance issue.
var supportADX = cpu.X86.HasADX && cpu.X86.HasBMI2
//go:noescape
func addMulVVW256(z, x *uint, y uint) (c uint)
//go:noescape
func addMulVVW1024(z, x *uint, y uint) (c uint)
//go:noescape
func addMulVVW1536(z, x *uint, y uint) (c uint)
//go:noescape
func addMulVVW2048(z, x *uint, y uint) (c uint)

View File

@ -0,0 +1,31 @@
package bigmod
func (x *Nat) Set(y *Nat) *Nat {
return x.set(y)
}
// SetOverflowedBytes assigns x = (b mode (m-1)) + 1, where b is a slice of big-endian bytes.
//
// The output will be resized to the size of m and overwritten.
//
//go:norace
func (x *Nat) SetOverflowedBytes(b []byte, m *Modulus) *Nat {
mMinusOne := NewNat().set(m.nat)
mMinusOne.limbs[0]-- // due to m is odd, so we can safely subtract 1
mMinusOneM, _ := NewModulus(mMinusOne.Bytes(m))
one := NewNat().resetFor(m)
one.limbs[0] = 1
x.resetToBytes(b)
x = NewNat().Mod(x, mMinusOneM) // x = x mod (m-1)
x.add(one) // we can safely add 1, no need to check overflow
return x
}
// CmpGeq returns 1 if x >= y, and 0 otherwise.
//
// Both operands must have the same announced length.
//
//go:norace
func (x *Nat) CmpGeq(y *Nat) choice {
return x.cmpGeq(y)
}

View File

@ -0,0 +1,42 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build purego || !(386 || amd64 || arm || arm64 || ppc64 || ppc64le || riscv64 || s390x)
package bigmod
import "unsafe"
// TODO: will use unsafe.Slice directly once upgrade golang sdk to 1.17+
func slice256(ptr *uint) []uint {
return (*[256 / _W]uint)(unsafe.Pointer(ptr))[:]
}
func slice1024(ptr *uint) []uint {
return (*[1024 / _W]uint)(unsafe.Pointer(ptr))[:]
}
func slice1536(ptr *uint) []uint {
return (*[1536 / _W]uint)(unsafe.Pointer(ptr))[:]
}
func slice2048(ptr *uint) []uint {
return (*[2048 / _W]uint)(unsafe.Pointer(ptr))[:]
}
func addMulVVW256(z, x *uint, y uint) (c uint) {
return addMulVVW(slice256(z), slice256(x), y)
}
func addMulVVW1024(z, x *uint, y uint) (c uint) {
return addMulVVW(slice1024(z), slice1024(x), y)
}
func addMulVVW1536(z, x *uint, y uint) (c uint) {
return addMulVVW(slice1536(z), slice1536(x), y)
}
func addMulVVW2048(z, x *uint, y uint) (c uint) {
return addMulVVW(slice2048(z), slice2048(x), y)
}

View File

@ -0,0 +1,87 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !purego && (ppc64 || ppc64le)
#include "textflag.h"
// func addMulVVW256(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW256(SB), $0-32
MOVD $1, R6 // R6 = z_len/4
JMP addMulVVWy<>(SB)
// func addMulVVW1024(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1024(SB), $0-32
MOVD $4, R6 // R6 = z_len/4
JMP addMulVVWy<>(SB)
// func addMulVVW1536(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1536(SB), $0-32
MOVD $6, R6 // R6 = z_len/4
JMP addMulVVWy<>(SB)
// func addMulVVW2048(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW2048(SB), $0-32
MOVD $8, R6 // R6 = z_len/4
JMP addMulVVWy<>(SB)
// This local function expects to be called only by
// callers above. R6 contains the z length/4
// since 4 values are processed for each
// loop iteration, and is guaranteed to be > 0.
// If other callers are added this function might
// need to change.
TEXT addMulVVWy<>(SB), NOSPLIT, $0
MOVD z+0(FP), R3
MOVD x+8(FP), R4
MOVD y+16(FP), R5
MOVD $0, R9 // R9 = c = 0
MOVD R6, CTR // Initialize loop counter
PCALIGN $16
loop:
MOVD 0(R4), R14 // x[i]
MOVD 8(R4), R16 // x[i+1]
MOVD 16(R4), R18 // x[i+2]
MOVD 24(R4), R20 // x[i+3]
MOVD 0(R3), R15 // z[i]
MOVD 8(R3), R17 // z[i+1]
MOVD 16(R3), R19 // z[i+2]
MOVD 24(R3), R21 // z[i+3]
MULLD R5, R14, R10 // low x[i]*y
MULHDU R5, R14, R11 // high x[i]*y
ADDC R15, R10
ADDZE R11
ADDC R9, R10
ADDZE R11, R9
MULLD R5, R16, R14 // low x[i+1]*y
MULHDU R5, R16, R15 // high x[i+1]*y
ADDC R17, R14
ADDZE R15
ADDC R9, R14
ADDZE R15, R9
MULLD R5, R18, R16 // low x[i+2]*y
MULHDU R5, R18, R17 // high x[i+2]*y
ADDC R19, R16
ADDZE R17
ADDC R9, R16
ADDZE R17, R9
MULLD R5, R20, R18 // low x[i+3]*y
MULHDU R5, R20, R19 // high x[i+3]*y
ADDC R21, R18
ADDZE R19
ADDC R9, R18
ADDZE R19, R9
MOVD R10, 0(R3) // z[i]
MOVD R14, 8(R3) // z[i+1]
MOVD R16, 16(R3) // z[i+2]
MOVD R18, 24(R3) // z[i+3]
ADD $32, R3
ADD $32, R4
BDNZ loop
done:
MOVD R9, c+24(FP)
RET

View File

@ -0,0 +1,96 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !purego
#include "textflag.h"
// func addMulVVW256(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW256(SB),$0-32
MOV $4, X30
JMP addMulVVWy(SB)
// func addMulVVW1024(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1024(SB),$0-32
MOV $16, X30
JMP addMulVVWy(SB)
// func addMulVVW1536(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1536(SB),$0-32
MOV $24, X30
JMP addMulVVWy(SB)
// func addMulVVW2048(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW2048(SB),$0-32
MOV $32, X30
JMP addMulVVWy(SB)
TEXT addMulVVWy(SB),NOFRAME|NOSPLIT,$0
MOV z+0(FP), X5
MOV x+8(FP), X7
MOV y+16(FP), X6
MOV $0, X29
BEQZ X30, done
loop:
MOV 0*8(X5), X10 // z[0]
MOV 1*8(X5), X13 // z[1]
MOV 2*8(X5), X16 // z[2]
MOV 3*8(X5), X19 // z[3]
MOV 0*8(X7), X8 // x[0]
MOV 1*8(X7), X11 // x[1]
MOV 2*8(X7), X14 // x[2]
MOV 3*8(X7), X17 // x[3]
MULHU X8, X6, X9 // z_hi[0] = x[0] * y
MUL X8, X6, X8 // z_lo[0] = x[0] * y
ADD X8, X10, X21 // z_lo[0] = x[0] * y + z[0]
SLTU X8, X21, X22
ADD X9, X22, X9 // z_hi[0] = x[0] * y + z[0]
ADD X21, X29, X10 // z_lo[0] = x[0] * y + z[0] + c
SLTU X21, X10, X22
ADD X9, X22, X29 // next c
MULHU X11, X6, X12 // z_hi[1] = x[1] * y
MUL X11, X6, X11 // z_lo[1] = x[1] * y
ADD X11, X13, X21 // z_lo[1] = x[1] * y + z[1]
SLTU X11, X21, X22
ADD X12, X22, X12 // z_hi[1] = x[1] * y + z[1]
ADD X21, X29, X13 // z_lo[1] = x[1] * y + z[1] + c
SLTU X21, X13, X22
ADD X12, X22, X29 // next c
MULHU X14, X6, X15 // z_hi[2] = x[2] * y
MUL X14, X6, X14 // z_lo[2] = x[2] * y
ADD X14, X16, X21 // z_lo[2] = x[2] * y + z[2]
SLTU X14, X21, X22
ADD X15, X22, X15 // z_hi[2] = x[2] * y + z[2]
ADD X21, X29, X16 // z_lo[2] = x[2] * y + z[2] + c
SLTU X21, X16, X22
ADD X15, X22, X29 // next c
MULHU X17, X6, X18 // z_hi[3] = x[3] * y
MUL X17, X6, X17 // z_lo[3] = x[3] * y
ADD X17, X19, X21 // z_lo[3] = x[3] * y + z[3]
SLTU X17, X21, X22
ADD X18, X22, X18 // z_hi[3] = x[3] * y + z[3]
ADD X21, X29, X19 // z_lo[3] = x[3] * y + z[3] + c
SLTU X21, X19, X22
ADD X18, X22, X29 // next c
MOV X10, 0*8(X5) // z[0]
MOV X13, 1*8(X5) // z[1]
MOV X16, 2*8(X5) // z[2]
MOV X19, 3*8(X5) // z[3]
ADD $32, X5
ADD $32, X7
SUB $4, X30
BNEZ X30, loop
done:
MOV X29, c+24(FP)
RET

View File

@ -0,0 +1,90 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !purego
#include "textflag.h"
// func addMulVVW256(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW256(SB), $0-32
MOVD $4, R5
JMP addMulVVWy(SB)
// func addMulVVW1024(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1024(SB), $0-32
MOVD $16, R5
JMP addMulVVWy(SB)
// func addMulVVW1536(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW1536(SB), $0-32
MOVD $24, R5
JMP addMulVVWy(SB)
// func addMulVVW2048(z, x *uint, y uint) (c uint)
TEXT ·addMulVVW2048(SB), $0-32
MOVD $32, R5
JMP addMulVVWy(SB)
TEXT addMulVVWy(SB), NOFRAME|NOSPLIT, $0
MOVD z+0(FP), R2
MOVD x+8(FP), R8
MOVD y+16(FP), R9
MOVD $0, R1 // i*8 = 0
MOVD $0, R7 // i = 0
MOVD $0, R0 // make sure it's zero
MOVD $0, R4 // c = 0
MOVD R5, R12
AND $-2, R12
CMPBGE R5, $2, A6
BR E6
A6:
MOVD (R8)(R1*1), R6
MULHDU R9, R6
MOVD (R2)(R1*1), R10
ADDC R10, R11 // add to low order bits
ADDE R0, R6
ADDC R4, R11
ADDE R0, R6
MOVD R6, R4
MOVD R11, (R2)(R1*1)
MOVD (8)(R8)(R1*1), R6
MULHDU R9, R6
MOVD (8)(R2)(R1*1), R10
ADDC R10, R11 // add to low order bits
ADDE R0, R6
ADDC R4, R11
ADDE R0, R6
MOVD R6, R4
MOVD R11, (8)(R2)(R1*1)
ADD $16, R1 // i*8 + 8
ADD $2, R7 // i++
CMPBLT R7, R12, A6
BR E6
L6:
// TODO: drop unused single-step loop.
MOVD (R8)(R1*1), R6
MULHDU R9, R6
MOVD (R2)(R1*1), R10
ADDC R10, R11 // add to low order bits
ADDE R0, R6
ADDC R4, R11
ADDE R0, R6
MOVD R6, R4
MOVD R11, (R2)(R1*1)
ADD $8, R1 // i*8 + 8
ADD $1, R7 // i++
E6:
CMPBLT R7, R5, L6 // i < n
MOVD R4, c+24(FP)
RET

824
internal/bigmod/nat_test.go Normal file
View File

@ -0,0 +1,824 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bigmod
import (
"bufio"
"bytes"
cryptorand "crypto/rand"
"encoding/hex"
"fmt"
"math/big"
"math/bits"
"math/rand"
"os"
"reflect"
"strings"
"testing"
"testing/quick"
)
// setBig assigns x = n, optionally resizing n to the appropriate size.
//
// The announced length of x is set based on the actual bit size of the input,
// ignoring leading zeroes.
func (x *Nat) setBig(n *big.Int) *Nat {
limbs := n.Bits()
x.reset(len(limbs))
for i := range limbs {
x.limbs[i] = uint(limbs[i])
}
return x
}
func (n *Nat) asBig() *big.Int {
bits := make([]big.Word, len(n.limbs))
for i := range n.limbs {
bits[i] = big.Word(n.limbs[i])
}
return new(big.Int).SetBits(bits)
}
func (n *Nat) String() string {
var limbs []string
for i := range n.limbs {
limbs = append(limbs, fmt.Sprintf("%016X", n.limbs[len(n.limbs)-1-i]))
}
return "{" + strings.Join(limbs, " ") + "}"
}
// Generate generates an even nat. It's used by testing/quick to produce random
// *nat values for quick.Check invocations.
func (*Nat) Generate(r *rand.Rand, size int) reflect.Value {
limbs := make([]uint, size)
for i := 0; i < size; i++ {
limbs[i] = uint(r.Uint64()) & ((1 << _W) - 2)
}
return reflect.ValueOf(&Nat{limbs})
}
func testModAddCommutative(a *Nat, b *Nat) bool {
m := maxModulus(uint(len(a.limbs)))
aPlusB := new(Nat).set(a)
aPlusB.Add(b, m)
bPlusA := new(Nat).set(b)
bPlusA.Add(a, m)
return aPlusB.Equal(bPlusA) == 1
}
func TestModAddCommutative(t *testing.T) {
err := quick.Check(testModAddCommutative, &quick.Config{})
if err != nil {
t.Error(err)
}
}
func testModSubThenAddIdentity(a *Nat, b *Nat) bool {
m := maxModulus(uint(len(a.limbs)))
original := new(Nat).set(a)
a.Sub(b, m)
a.Add(b, m)
return a.Equal(original) == 1
}
func TestModSubThenAddIdentity(t *testing.T) {
err := quick.Check(testModSubThenAddIdentity, &quick.Config{})
if err != nil {
t.Error(err)
}
}
func TestMontgomeryRoundtrip(t *testing.T) {
err := quick.Check(func(a *Nat) bool {
one := &Nat{make([]uint, len(a.limbs))}
one.limbs[0] = 1
aPlusOne := new(big.Int).SetBytes(natBytes(a))
aPlusOne.Add(aPlusOne, big.NewInt(1))
m, _ := NewModulus(aPlusOne.Bytes())
monty := new(Nat).set(a)
monty.montgomeryRepresentation(m)
aAgain := new(Nat).set(monty)
aAgain.montgomeryMul(monty, one, m)
if a.Equal(aAgain) != 1 {
t.Errorf("%v != %v", a, aAgain)
return false
}
return true
}, &quick.Config{})
if err != nil {
t.Error(err)
}
}
func TestShiftIn(t *testing.T) {
if bits.UintSize != 64 {
t.Skip("examples are only valid in 64 bit")
}
examples := []struct {
m, x, expected []byte
y uint64
}{{
m: []byte{13},
x: []byte{0},
y: 0xFFFF_FFFF_FFFF_FFFF,
expected: []byte{2},
}, {
m: []byte{13},
x: []byte{7},
y: 0xFFFF_FFFF_FFFF_FFFF,
expected: []byte{10},
}, {
m: []byte{0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d},
x: make([]byte, 9),
y: 0xFFFF_FFFF_FFFF_FFFF,
expected: []byte{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
}, {
m: []byte{0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d},
x: []byte{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
y: 0,
expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06},
}}
for i, tt := range examples {
m := modulusFromBytes(tt.m)
got := natFromBytes(tt.x).ExpandFor(m).shiftIn(uint(tt.y), m)
if exp := natFromBytes(tt.expected).ExpandFor(m); got.Equal(exp) != 1 {
t.Errorf("%d: got %v, expected %v", i, got, exp)
}
}
}
func TestModulusAndNatSizes(t *testing.T) {
// These are 126 bit (2 * _W on 64-bit architectures) values, serialized as
// 128 bits worth of bytes. If leading zeroes are stripped, they fit in two
// limbs, if they are not, they fit in three. This can be a problem because
// modulus strips leading zeroes and nat does not.
m := modulusFromBytes([]byte{
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})
xb := []byte{0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}
natFromBytes(xb).ExpandFor(m) // must not panic for shrinking
NewNat().SetBytes(xb, m)
}
func TestSetBytes(t *testing.T) {
tests := []struct {
m, b []byte
fail bool
}{{
m: []byte{0xff, 0xff},
b: []byte{0x00, 0x01},
}, {
m: []byte{0xff, 0xff},
b: []byte{0xff, 0xff},
fail: true,
}, {
m: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
b: []byte{0x00, 0x01},
}, {
m: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
b: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe},
}, {
m: []byte{0xff, 0xff},
b: []byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
fail: true,
}, {
m: []byte{0xff, 0xff},
b: []byte{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
fail: true,
}, {
m: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
b: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe},
}, {
m: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
b: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe},
fail: true,
}, {
m: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
b: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
fail: true,
}, {
m: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
b: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe},
fail: true,
}, {
m: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd},
b: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
fail: true,
}}
for i, tt := range tests {
m := modulusFromBytes(tt.m)
got, err := NewNat().SetBytes(tt.b, m)
if err != nil {
if !tt.fail {
t.Errorf("%d: unexpected error: %v", i, err)
}
continue
}
if tt.fail {
t.Errorf("%d: unexpected success", i)
continue
}
if expected := natFromBytes(tt.b).ExpandFor(m); got.Equal(expected) != yes {
t.Errorf("%d: got %v, expected %v", i, got, expected)
}
}
f := func(xBytes []byte) bool {
m := maxModulus(uint(len(xBytes)*8/_W + 1))
got, err := NewNat().SetBytes(xBytes, m)
if err != nil {
return false
}
return got.Equal(natFromBytes(xBytes).ExpandFor(m)) == yes
}
err := quick.Check(f, &quick.Config{})
if err != nil {
t.Error(err)
}
}
func TestExpand(t *testing.T) {
sliced := []uint{1, 2, 3, 4}
examples := []struct {
in []uint
n int
out []uint
}{{
[]uint{1, 2},
4,
[]uint{1, 2, 0, 0},
}, {
sliced[:2],
4,
[]uint{1, 2, 0, 0},
}, {
[]uint{1, 2},
2,
[]uint{1, 2},
}}
for i, tt := range examples {
got := (&Nat{tt.in}).expand(tt.n)
if len(got.limbs) != len(tt.out) || got.Equal(&Nat{tt.out}) != 1 {
t.Errorf("%d: got %v, expected %v", i, got, tt.out)
}
}
}
func TestMod(t *testing.T) {
m := modulusFromBytes([]byte{0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d})
x := natFromBytes([]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
out := new(Nat)
out.Mod(x, m)
expected := natFromBytes([]byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09})
if out.Equal(expected) != 1 {
t.Errorf("%+v != %+v", out, expected)
}
}
func TestModSub(t *testing.T) {
m := modulusFromBytes([]byte{13})
x := &Nat{[]uint{6}}
y := &Nat{[]uint{7}}
x.Sub(y, m)
expected := &Nat{[]uint{12}}
if x.Equal(expected) != 1 {
t.Errorf("%+v != %+v", x, expected)
}
x.Sub(y, m)
expected = &Nat{[]uint{5}}
if x.Equal(expected) != 1 {
t.Errorf("%+v != %+v", x, expected)
}
}
func TestModAdd(t *testing.T) {
m := modulusFromBytes([]byte{13})
x := &Nat{[]uint{6}}
y := &Nat{[]uint{7}}
x.Add(y, m)
expected := &Nat{[]uint{0}}
if x.Equal(expected) != 1 {
t.Errorf("%+v != %+v", x, expected)
}
x.Add(y, m)
expected = &Nat{[]uint{7}}
if x.Equal(expected) != 1 {
t.Errorf("%+v != %+v", x, expected)
}
}
func TestExp(t *testing.T) {
m := modulusFromBytes([]byte{13})
x := &Nat{[]uint{3}}
out := &Nat{[]uint{0}}
out.Exp(x, []byte{12}, m)
expected := &Nat{[]uint{1}}
if out.Equal(expected) != 1 {
t.Errorf("%+v != %+v", out, expected)
}
}
func TestExpShort(t *testing.T) {
m := modulusFromBytes([]byte{13})
x := &Nat{[]uint{3}}
out := &Nat{[]uint{0}}
out.ExpShortVarTime(x, 12, m)
expected := &Nat{[]uint{1}}
if out.Equal(expected) != 1 {
t.Errorf("%+v != %+v", out, expected)
}
}
// TestMulReductions tests that Mul reduces results equal or slightly greater
// than the modulus. Some Montgomery algorithms don't and need extra care to
// return correct results. See https://go.dev/issue/13907.
func TestMulReductions(t *testing.T) {
// Two short but multi-limb primes.
a, _ := new(big.Int).SetString("773608962677651230850240281261679752031633236267106044359907", 10)
b, _ := new(big.Int).SetString("180692823610368451951102211649591374573781973061758082626801", 10)
n := new(big.Int).Mul(a, b)
N, _ := NewModulus(n.Bytes())
A := NewNat().setBig(a).ExpandFor(N)
B := NewNat().setBig(b).ExpandFor(N)
if A.Mul(B, N).IsZero() != 1 {
t.Error("a * b mod (a * b) != 0")
}
i := new(big.Int).ModInverse(a, b)
N, _ = NewModulus(b.Bytes())
A = NewNat().setBig(a).ExpandFor(N)
I := NewNat().setBig(i).ExpandFor(N)
one := NewNat().setBig(big.NewInt(1)).ExpandFor(N)
if A.Mul(I, N).Equal(one) != 1 {
t.Error("a * inv(a) mod b != 1")
}
}
func TestMul(t *testing.T) {
t.Run("760", func(t *testing.T) { testMul(t, 760/8) })
t.Run("256", func(t *testing.T) { testMul(t, 256/8) })
t.Run("1024", func(t *testing.T) { testMul(t, 1024/8) })
t.Run("1536", func(t *testing.T) { testMul(t, 1536/8) })
t.Run("2048", func(t *testing.T) { testMul(t, 2048/8) })
}
func testMul(t *testing.T, n int) {
a, b, m := make([]byte, n), make([]byte, n), make([]byte, n)
cryptorand.Read(a)
cryptorand.Read(b)
cryptorand.Read(m)
// Pick the highest as the modulus.
if bytes.Compare(a, m) > 0 {
a, m = m, a
}
if bytes.Compare(b, m) > 0 {
b, m = m, b
}
M, err := NewModulus(m)
if err != nil {
t.Fatal(err)
}
A, err := NewNat().SetBytes(a, M)
if err != nil {
t.Fatal(err)
}
B, err := NewNat().SetBytes(b, M)
if err != nil {
t.Fatal(err)
}
A.Mul(B, M)
ABytes := A.Bytes(M)
mBig := new(big.Int).SetBytes(m)
aBig := new(big.Int).SetBytes(a)
bBig := new(big.Int).SetBytes(b)
nBig := new(big.Int).Mul(aBig, bBig)
nBig.Mod(nBig, mBig)
nBigBytes := make([]byte, len(ABytes))
nBig.FillBytes(nBigBytes)
if !bytes.Equal(ABytes, nBigBytes) {
t.Errorf("got %x, want %x", ABytes, nBigBytes)
}
}
func TestIs(t *testing.T) {
checkYes := func(c choice, err string) {
t.Helper()
if c != yes {
t.Error(err)
}
}
checkNot := func(c choice, err string) {
t.Helper()
if c != no {
t.Error(err)
}
}
mFour := modulusFromBytes([]byte{4})
n, err := NewNat().SetBytes([]byte{3}, mFour)
if err != nil {
t.Fatal(err)
}
checkYes(n.IsMinusOne(mFour), "3 is not -1 mod 4")
checkNot(n.IsZero(), "3 is zero")
checkNot(n.IsOne(), "3 is one")
checkYes(n.IsOdd(), "3 is not odd")
n.SubOne(mFour)
checkNot(n.IsMinusOne(mFour), "2 is -1 mod 4")
checkNot(n.IsZero(), "2 is zero")
checkNot(n.IsOne(), "2 is one")
checkNot(n.IsOdd(), "2 is odd")
n.SubOne(mFour)
checkNot(n.IsMinusOne(mFour), "1 is -1 mod 4")
checkNot(n.IsZero(), "1 is zero")
checkYes(n.IsOne(), "1 is not one")
checkYes(n.IsOdd(), "1 is not odd")
n.SubOne(mFour)
checkNot(n.IsMinusOne(mFour), "0 is -1 mod 4")
checkYes(n.IsZero(), "0 is not zero")
checkNot(n.IsOne(), "0 is one")
checkNot(n.IsOdd(), "0 is odd")
n.SubOne(mFour)
checkYes(n.IsMinusOne(mFour), "-1 is not -1 mod 4")
checkNot(n.IsZero(), "-1 is zero")
checkNot(n.IsOne(), "-1 is one")
checkYes(n.IsOdd(), "-1 mod 4 is not odd")
mTwoLimbs := maxModulus(2)
n, err = NewNat().SetBytes([]byte{0x01}, mTwoLimbs)
if err != nil {
t.Fatal(err)
}
if n.IsOne() != 1 {
t.Errorf("1 is not one")
}
}
func TestTrailingZeroBits(t *testing.T) {
nb := new(big.Int).SetBytes([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e})
nb.Lsh(nb, 128)
expected := 129
for expected >= 0 {
n := NewNat().setBig(nb)
if n.TrailingZeroBitsVarTime() != uint(expected) {
t.Errorf("%d != %d", n.TrailingZeroBitsVarTime(), expected)
}
nb.Rsh(nb, 1)
expected--
}
}
func TestRightShift(t *testing.T) {
nb, err := cryptorand.Int(cryptorand.Reader, new(big.Int).Lsh(big.NewInt(1), 1024))
if err != nil {
t.Fatal(err)
}
for _, shift := range []uint{1, 32, 64, 128, 1024 - 128, 1024 - 64, 1024 - 32, 1024 - 1} {
testShift := func(t *testing.T, shift uint) {
n := NewNat().setBig(nb)
oldLen := len(n.limbs)
n.ShiftRightVarTime(shift)
if len(n.limbs) != oldLen {
t.Errorf("len(n.limbs) = %d, want %d", len(n.limbs), oldLen)
}
exp := new(big.Int).Rsh(nb, shift)
if n.asBig().Cmp(exp) != 0 {
t.Errorf("%v != %v", n.asBig(), exp)
}
}
t.Run(fmt.Sprint(shift-1), func(t *testing.T) { testShift(t, shift-1) })
t.Run(fmt.Sprint(shift), func(t *testing.T) { testShift(t, shift) })
t.Run(fmt.Sprint(shift+1), func(t *testing.T) { testShift(t, shift+1) })
}
}
func natBytes(n *Nat) []byte {
return n.Bytes(maxModulus(uint(len(n.limbs))))
}
func natFromBytes(b []byte) *Nat {
// Must not use Nat.SetBytes as it's used in TestSetBytes.
bb := new(big.Int).SetBytes(b)
return NewNat().setBig(bb)
}
func modulusFromBytes(b []byte) *Modulus {
bb := new(big.Int).SetBytes(b)
m, _ := NewModulus(bb.Bytes())
return m
}
// maxModulus returns the biggest modulus that can fit in n limbs.
func maxModulus(n uint) *Modulus {
b := big.NewInt(1)
b.Lsh(b, n*_W)
b.Sub(b, big.NewInt(1))
m, _ := NewModulus(b.Bytes())
return m
}
func makeBenchmarkModulus(n uint) *Modulus {
return maxModulus(n)
}
func makeBenchmarkValue(n int) *Nat {
x := make([]uint, n)
for i := 0; i < n; i++ {
x[i]--
}
return &Nat{limbs: x}
}
func makeBenchmarkExponent() []byte {
e := make([]byte, 256)
for i := 0; i < 32; i++ {
e[i] = 0xFF
}
return e
}
func BenchmarkRR256(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
makeBenchmarkModulus(4)
}
}
func BenchmarkModAdd(b *testing.B) {
x := makeBenchmarkValue(32)
y := makeBenchmarkValue(32)
m := makeBenchmarkModulus(32)
b.ResetTimer()
for i := 0; i < b.N; i++ {
x.Add(y, m)
}
}
func BenchmarkModSub(b *testing.B) {
x := makeBenchmarkValue(32)
y := makeBenchmarkValue(32)
m := makeBenchmarkModulus(32)
b.ResetTimer()
for i := 0; i < b.N; i++ {
x.Sub(y, m)
}
}
func BenchmarkMontgomeryRepr(b *testing.B) {
x := makeBenchmarkValue(32)
m := makeBenchmarkModulus(32)
b.ResetTimer()
for i := 0; i < b.N; i++ {
x.montgomeryRepresentation(m)
}
}
func BenchmarkMontgomeryMul(b *testing.B) {
x := makeBenchmarkValue(32)
y := makeBenchmarkValue(32)
out := makeBenchmarkValue(32)
m := makeBenchmarkModulus(32)
b.ResetTimer()
for i := 0; i < b.N; i++ {
out.montgomeryMul(x, y, m)
}
}
func BenchmarkModMul(b *testing.B) {
x := makeBenchmarkValue(32)
y := makeBenchmarkValue(32)
m := makeBenchmarkModulus(32)
b.ResetTimer()
for i := 0; i < b.N; i++ {
x.Mul(y, m)
}
}
func BenchmarkModMul256(b *testing.B) {
x := makeBenchmarkValue(4)
y := makeBenchmarkValue(4)
m := makeBenchmarkModulus(4)
b.ResetTimer()
for i := 0; i < b.N; i++ {
x.Mul(y, m)
}
}
func BenchmarkExpBig(b *testing.B) {
out := new(big.Int)
exponentBytes := makeBenchmarkExponent()
x := new(big.Int).SetBytes(exponentBytes)
e := new(big.Int).SetBytes(exponentBytes)
n := new(big.Int).SetBytes(exponentBytes)
one := new(big.Int).SetUint64(1)
n.Add(n, one)
b.ResetTimer()
for i := 0; i < b.N; i++ {
out.Exp(x, e, n)
}
}
func BenchmarkExp(b *testing.B) {
x := makeBenchmarkValue(32)
e := makeBenchmarkExponent()
out := makeBenchmarkValue(32)
m := makeBenchmarkModulus(32)
b.ResetTimer()
for i := 0; i < b.N; i++ {
out.Exp(x, e, m)
}
}
func TestNewModulus(t *testing.T) {
expected := "modulus must be > 1"
_, err := NewModulus([]byte{})
if err == nil || err.Error() != expected {
t.Errorf("NewModulus(0) got %q, want %q", err, expected)
}
_, err = NewModulus([]byte{0})
if err == nil || err.Error() != expected {
t.Errorf("NewModulus(0) got %q, want %q", err, expected)
}
_, err = NewModulus([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
if err == nil || err.Error() != expected {
t.Errorf("NewModulus(0) got %q, want %q", err, expected)
}
_, err = NewModulus([]byte{1})
if err == nil || err.Error() != expected {
t.Errorf("NewModulus(1) got %q, want %q", err, expected)
}
_, err = NewModulus([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
if err == nil || err.Error() != expected {
t.Errorf("NewModulus(1) got %q, want %q", err, expected)
}
}
func TestOverflowedBytes(t *testing.T) {
cases := []string{
"b640000002a3a6f1d603ab4ff58ec74449f2934b18ea8beee56ee19cd69ecf25",
"b640000002a3a6f1d603ab4ff58ec74449f2934b18ea8beee56ee19cd69ecf23",
"b640000002a3a6f1d603ab4ff58ec74449f2934b18ea8beee56ee19cd69ecf24",
"b640000002a3a6f1d603ab4ff58ec74449f2934b18ea8beee56ee19cd69ecf24b640000002a3a6f1",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"00",
}
mBytes, _ := hex.DecodeString(cases[0])
m, err := NewModulus(mBytes)
if err != nil {
t.Fatal(err)
}
bigOne := big.NewInt(1)
mBigInt := new(big.Int).SetBytes(mBytes)
mMinusOne := new(big.Int).Sub(mBigInt, bigOne)
for _, c := range cases {
d, _ := hex.DecodeString(c)
k := new(big.Int).SetBytes(d)
k = new(big.Int).Mod(k, mMinusOne)
k = new(big.Int).Add(k, bigOne)
k = new(big.Int).Mod(k, mBigInt)
kNat := NewNat().SetOverflowedBytes(d, m)
k2 := new(big.Int).SetBytes(kNat.Bytes(m))
if !bytes.Equal(k2.Bytes(), k.Bytes()) {
t.Errorf("%s, expected %x, got %x", c, k.Bytes(), k2.Bytes())
}
}
}
func makeTestValue(nbits int) []uint {
n := nbits / _W
x := make([]uint, n)
for i := 0; i < n; i++ {
x[i]--
}
return x
}
func slicesEqual(a, b []uint) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
func TestAddMulVVWSized(t *testing.T) {
// Sized addMulVVW have architecture-specific implementations on
// a number of architectures. Test that they match the generic
// implementation.
tests := []struct {
n int
f func(z, x *uint, y uint) uint
}{
{256, addMulVVW256},
{1024, addMulVVW1024},
{1536, addMulVVW1536},
{2048, addMulVVW2048},
}
for _, test := range tests {
t.Run(fmt.Sprint(test.n), func(t *testing.T) {
x := makeTestValue(test.n)
z := makeTestValue(test.n)
z2 := makeTestValue(test.n)
var y uint
y--
c := addMulVVW(z, x, y)
c2 := test.f(&z2[0], &x[0], y)
if !slicesEqual(z, z2) || c != c2 {
t.Errorf("%016X, %016X != %016X, %016X", z, c, z2, c2)
}
})
}
}
func TestInverse(t *testing.T) {
f, err := os.Open("testdata/mod_inv_tests.txt")
if err != nil {
t.Fatal(err)
}
var ModInv, A, M string
var lineNum int
scanner := bufio.NewScanner(f)
for scanner.Scan() {
lineNum++
line := scanner.Text()
if len(line) == 0 || line[0] == '#' {
continue
}
k, v, _ := strings.Cut(line, " = ")
switch k {
case "ModInv":
ModInv = v
case "A":
A = v
case "M":
M = v
t.Run(fmt.Sprintf("line %d", lineNum), func(t *testing.T) {
m, err := NewModulus(decodeHex(t, M))
if err != nil {
t.Skip("modulus <= 1")
}
a, err := NewNat().SetBytes(decodeHex(t, A), m)
if err != nil {
t.Fatal(err)
}
got, ok := NewNat().InverseVarTime(a, m)
if !ok {
t.Fatal("not invertible")
}
exp, err := NewNat().SetBytes(decodeHex(t, ModInv), m)
if err != nil {
t.Fatal(err)
}
if got.Equal(exp) != 1 {
t.Errorf("%v != %v", got, exp)
}
})
default:
t.Fatalf("unknown key %q on line %d", k, lineNum)
}
}
if err := scanner.Err(); err != nil {
t.Fatal(err)
}
}
func decodeHex(t *testing.T, s string) []byte {
t.Helper()
if len(s)%2 != 0 {
s = "0" + s
}
b, err := hex.DecodeString(s)
if err != nil {
t.Fatalf("failed to decode hex %q: %v", s, err)
}
return b
}

View File

@ -0,0 +1,115 @@
# ModInv tests.
#
# These test vectors satisfy ModInv * A = 1 (mod M) and 0 <= ModInv < M.
ModInv = 00
A = 00
M = 01
ModInv = 00
A = 01
M = 01
ModInv = 00
A = 02
M = 01
ModInv = 00
A = 03
M = 01
ModInv = 64
A = 54
M = e3
ModInv = 13
A = 2b
M = 30
ModInv = 2f
A = 30
M = 37
ModInv = 4
A = 13
M = 4b
ModInv = 1c47
A = cd4
M = 6a21
ModInv = 2b97
A = 8e7
M = 49c0
ModInv = 29b9
A = fcb
M = 3092
ModInv = a83
A = 14bf
M = 41ae
ModInv = 18f15fe1
A = 11b5d53e
M = 322e92a1
ModInv = 32f9453b
A = 8af6df6
M = 33d45eb7
ModInv = d696369
A = c5f89dd5
M = fc09c17c
ModInv = 622839d8
A = 60c2526
M = 74200493
ModInv = fb5a8aee7bbc4ef
A = 24ebd835a70be4e2
M = 9c7256574e0c5e93
ModInv = 846bc225402419c
A = 23026003ab1fbdb
M = 1683cbe32779c59b
ModInv = 5ff84f63a78982f9
A = 4a2420dc733e1a0f
M = a73c6bfabefa09e6
ModInv = 133e74d28ef42b43
A = 2e9511ae29cdd41
M = 15234df99f19fcda
ModInv = 46ae1fabe9521e4b99b198fc8439609023aa69be2247c0d1e27c2a0ea332f9c5
A = 6331fec5f01014046788c919ed50dc86ac7a80c085f1b6f645dd179c0f0dc9cd
M = 8ef409de82318259a8655a39293b1e762fa2cc7e0aeb4c59713a1e1fff6af640
ModInv = 444ccea3a7b21677dd294d34de53cc8a5b51e69b37782310a00fc6bcc975709b
A = 679280bd880994c08322143a4ea8a0825d0466fda1bb6b3eb86fc8e90747512b
M = e4fecab84b365c63a0dab4244ce3f921a9c87ec64d69a2031939f55782e99a2e
ModInv = 1ac7d7a03ceec5f690f567c9d61bf3469c078285bcc5cf00ac944596e887ca17
A = 1593ef32d9c784f5091bdff952f5c5f592a3aed6ba8ea865efa6d7df87be1805
M = 1e276882f90c95e0c1976eb079f97af075445b1361c02018d6bd7191162e67b2
ModInv = 639108b90dfe946f498be21303058413bbb0e59d0bd6a6115788705abd0666d6
A = 9258d6238e4923d120b2d1033573ffcac691526ad0842a3b174dccdbb79887bd
M = ce62909c39371d463aaba3d4b72ea6da49cb9b529e39e1972ef3ccd9a66fe08f
ModInv = aebde7654cb17833a106231c4b9e2f519140e85faee1bfb4192830f03f385e773c0f4767e93e874ffdc3b7a6b7e6a710e5619901c739ee8760a26128e8c91ef8cf761d0e505d8b28ae078d17e6071c372893bb7b72538e518ebc57efa70b7615e406756c49729b7c6e74f84aed7a316b6fa748ff4b9f143129d29dad1bff98bb
A = a29dacaf5487d354280fdd2745b9ace4cd50f2bde41d0ee529bf26a1913244f708085452ff32feab19a7418897990da46a0633f7c8375d583367319091bbbe069b0052c5e48a7daac9fb650db5af768cd2508ec3e2cda7456d4b9ce1c39459627a8b77e038b826cd7e326d0685b0cd0cb50f026f18300dae9f5fd42aa150ee8b
M = d686f9b86697313251685e995c09b9f1e337ddfaa050bd2df15bf4ca1dc46c5565021314765299c434ea1a6ec42bf92a29a7d1ffff599f4e50b79a82243fb24813060580c770d4c1140aeb2ab2685007e948b6f1f62e8001a0545619477d498132c907774479f6d95899e6251e7136f79ab6d3b7c82e4aca421e7d22fe7db19c
ModInv = 1ec872f4f20439e203597ca4de9d1296743f95781b2fe85d5def808558bbadef02a46b8955f47c83e1625f8bb40228eab09cad2a35c9ad62ab77a30e3932872959c5898674162da244a0ec1f68c0ed89f4b0f3572bfdc658ad15bf1b1c6e1176b0784c9935bd3ff1f49bb43753eacee1d8ca1c0b652d39ec727da83984fe3a0f
A = 2e527b0a1dc32460b2dd94ec446c692989f7b3c7451a5cbeebf69fc0ea9c4871fbe78682d5dc5b66689f7ed889b52161cd9830b589a93d21ab26dbede6c33959f5a0f0d107169e2daaac78bac8cf2d41a1eb1369cb6dc9e865e73bb2e51b886f4e896082db199175e3dde0c4ed826468f238a77bd894245d0918efc9ca84f945
M = b13133a9ebe0645f987d170c077eea2aa44e85c9ab10386d02867419a590cb182d9826a882306c212dbe75225adde23f80f5b37ca75ed09df20fc277cc7fbbfac8d9ef37a50f6b68ea158f5447283618e64e1426406d26ea85232afb22bf546c75018c1c55cb84c374d58d9d44c0a13ba88ac2e387765cb4c3269e3a983250fa
ModInv = 30ffa1876313a69de1e4e6ee132ea1d3a3da32f3b56f5cfb11402b0ad517dce605cf8e91d69fa375dd887fa8507bd8a28b2d5ce745799126e86f416047709f93f07fbd88918a047f13100ea71b1d48f6fc6d12e5c917646df3041b302187af641eaedf4908abc36f12c204e1526a7d80e96e302fb0779c28d7da607243732f26
A = 31157208bde6b85ebecaa63735947b3b36fa351b5c47e9e1c40c947339b78bf96066e5dbe21bb42629e6fcdb81f5f88db590bfdd5f4c0a6a0c3fc6377e5c1fd8235e46e291c688b6d6ecfb36604891c2a7c9cbcc58c26e44b43beecb9c5044b58bb58e35de3cf1128f3c116534fe4e421a33f83603c3df1ae36ec88092f67f2a
M = 53408b23d6cb733e6c9bc3d1e2ea2286a5c83cc4e3e7470f8af3a1d9f28727f5b1f8ae348c1678f5d1105dc3edf2de64e65b9c99545c47e64b770b17c8b4ef5cf194b43a0538053e87a6b95ade1439cebf3d34c6aa72a11c1497f58f76011e16c5be087936d88aba7a740113120e939e27bd3ddcb6580c2841aa406566e33c35
ModInv = 87355002f305c81ba0dc97ca2234a2bc02528cefde38b94ac5bd95efc7bf4c140899107fff47f0df9e3c6aa70017ebc90610a750f112cd4f475b9c76b204a953444b4e7196ccf17e93fdaed160b7345ca9b397eddf9446e8ea8ee3676102ce70eaafbe9038a34639789e6f2f1e3f352638f2e8a8f5fc56aaea7ec705ee068dd5
A = 42a25d0bc96f71750f5ac8a51a1605a41b506cca51c9a7ecf80cad713e56f70f1b4b6fa51cbb101f55fd74f318adefb3af04e0c8a7e281055d5a40dd40913c0e1211767c5be915972c73886106dc49325df6c2df49e9eea4536f0343a8e7d332c6159e4f5bdb20d89f90e67597c4a2a632c31b2ef2534080a9ac61f52303990d
M = d3d3f95d50570351528a76ab1e806bae1968bd420899bdb3d87c823fac439a4354c31f6c888c939784f18fe10a95e6d203b1901caa18937ba6f8be033af10c35fc869cf3d16bef479f280f53b3499e645d0387554623207ca4989e5de00bfeaa5e9ab56474fc60dd4967b100e0832eaaf2fcb2ef82a181567057b880b3afef62

View File

@ -0,0 +1,149 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package byteorder provides functions for decoding and encoding
// little and big endian integer types from/to byte slices.
package byteorder
func LEUint16(b []byte) uint16 {
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint16(b[0]) | uint16(b[1])<<8
}
func LEPutUint16(b []byte, v uint16) {
_ = b[1] // early bounds check to guarantee safety of writes below
b[0] = byte(v)
b[1] = byte(v >> 8)
}
func LEAppendUint16(b []byte, v uint16) []byte {
return append(b,
byte(v),
byte(v>>8),
)
}
func LEUint32(b []byte) uint32 {
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}
func LEPutUint32(b []byte, v uint32) {
_ = b[3] // early bounds check to guarantee safety of writes below
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
b[3] = byte(v >> 24)
}
func LEAppendUint32(b []byte, v uint32) []byte {
return append(b,
byte(v),
byte(v>>8),
byte(v>>16),
byte(v>>24),
)
}
func LEUint64(b []byte) uint64 {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
}
func LEPutUint64(b []byte, v uint64) {
_ = b[7] // early bounds check to guarantee safety of writes below
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
b[3] = byte(v >> 24)
b[4] = byte(v >> 32)
b[5] = byte(v >> 40)
b[6] = byte(v >> 48)
b[7] = byte(v >> 56)
}
func LEAppendUint64(b []byte, v uint64) []byte {
return append(b,
byte(v),
byte(v>>8),
byte(v>>16),
byte(v>>24),
byte(v>>32),
byte(v>>40),
byte(v>>48),
byte(v>>56),
)
}
func BEUint16(b []byte) uint16 {
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint16(b[1]) | uint16(b[0])<<8
}
func BEPutUint16(b []byte, v uint16) {
_ = b[1] // early bounds check to guarantee safety of writes below
b[0] = byte(v >> 8)
b[1] = byte(v)
}
func BEAppendUint16(b []byte, v uint16) []byte {
return append(b,
byte(v>>8),
byte(v),
)
}
func BEUint32(b []byte) uint32 {
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
}
func BEPutUint32(b []byte, v uint32) {
_ = b[3] // early bounds check to guarantee safety of writes below
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
b[3] = byte(v)
}
func BEAppendUint32(b []byte, v uint32) []byte {
return append(b,
byte(v>>24),
byte(v>>16),
byte(v>>8),
byte(v),
)
}
func BEUint64(b []byte) uint64 {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
}
func BEPutUint64(b []byte, v uint64) {
_ = b[7] // early bounds check to guarantee safety of writes below
b[0] = byte(v >> 56)
b[1] = byte(v >> 48)
b[2] = byte(v >> 40)
b[3] = byte(v >> 32)
b[4] = byte(v >> 24)
b[5] = byte(v >> 16)
b[6] = byte(v >> 8)
b[7] = byte(v)
}
func BEAppendUint64(b []byte, v uint64) []byte {
return append(b,
byte(v>>56),
byte(v>>48),
byte(v>>40),
byte(v>>32),
byte(v>>24),
byte(v>>16),
byte(v>>8),
byte(v),
)
}

292
internal/cipher/xts/xts.go Normal file
View File

@ -0,0 +1,292 @@
// Package xts implements XTS encryption mode, as specified in IEEE P1619/D16 and GB/T 17964-2021.
package xts
import (
"crypto/cipher"
"crypto/subtle"
"errors"
"github.com/emmansun/gmsm/internal/alias"
)
const GF128_FDBK byte = 0x87
type concurrentBlocks interface {
Concurrency() int
EncryptBlocks(dst, src []byte)
DecryptBlocks(dst, src []byte)
}
// Cipher contains an expanded key structure. It is unsafe for concurrent use.
type xts struct {
b cipher.Block
tweak [blockSize]byte
isGB bool // if true, follows GB/T 17964-2021
}
// blockSize is the block size that the underlying cipher must have. XTS is
// only defined for 16-byte ciphers.
const blockSize = 16
type xtsEncrypter xts
// xtsEncAble is an interface implemented by ciphers that have a specific
// optimized implementation of XTS encryption, like sm4.
// NewXTSEncrypter will check for this interface and return the specific
// BlockMode if found.
type xtsEncAble interface {
NewXTSEncrypter(encryptedTweak *[blockSize]byte, isGB bool) cipher.BlockMode
}
func NewXTSEncrypter(cipherFunc func([]byte) (cipher.Block, error), key, tweakKey, tweak []byte, isGB bool) (cipher.BlockMode, error) {
if len(tweak) != blockSize {
return nil, errors.New("cipher: invalid tweak length")
}
k1, err := cipherFunc(key)
if err != nil {
return nil, err
}
if k1.BlockSize() != blockSize {
return nil, errors.New("cipher: cipher does not have a block size of 16")
}
k2, err := cipherFunc(tweakKey)
if err != nil {
return nil, err
}
if xtsable, ok := k1.(xtsEncAble); ok {
var encryptedTweak [blockSize]byte
k2.Encrypt(encryptedTweak[:], tweak)
return xtsable.NewXTSEncrypter(&encryptedTweak, isGB), nil
}
c := &xts{
b: k1,
isGB: isGB,
}
k2.Encrypt(c.tweak[:], tweak)
return (*xtsEncrypter)(c), nil
}
type xtsDecrypter xts
// xtsDecAble is an interface implemented by ciphers that have a specific
// optimized implementation of XTS encryption, like sm4.
// NewXTSDecrypter will check for this interface and return the specific
// BlockMode if found.
type xtsDecAble interface {
NewXTSDecrypter(encryptedTweak *[blockSize]byte, isGB bool) cipher.BlockMode
}
func NewXTSDecrypter(cipherFunc func([]byte) (cipher.Block, error), key, tweakKey, tweak []byte, isGB bool) (cipher.BlockMode, error) {
if len(tweak) != blockSize {
return nil, errors.New("cipher: invalid tweak length")
}
k1, err := cipherFunc(key)
if err != nil {
return nil, err
}
if k1.BlockSize() != blockSize {
return nil, errors.New("cipher: cipher does not have a block size of 16")
}
k2, err := cipherFunc(tweakKey)
if err != nil {
return nil, err
}
if xtsable, ok := k1.(xtsDecAble); ok {
var encryptedTweak [blockSize]byte
k2.Encrypt(encryptedTweak[:], tweak)
return xtsable.NewXTSDecrypter(&encryptedTweak, isGB), nil
}
c := &xts{
b: k1,
isGB: isGB,
}
k2.Encrypt(c.tweak[:], tweak)
return (*xtsDecrypter)(c), nil
}
func (c *xtsEncrypter) BlockSize() int {
return blockSize
}
// CryptBlocks encrypts a sector of plaintext and puts the result into ciphertext.
// Plaintext and ciphertext must overlap entirely or not at all.
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
func (c *xtsEncrypter) CryptBlocks(ciphertext, plaintext []byte) {
if len(ciphertext) < len(plaintext) {
panic("cipher: ciphertext is smaller than plaintext")
}
if len(plaintext) < blockSize {
panic("cipher: plaintext length is smaller than the block size")
}
if alias.InexactOverlap(ciphertext[:len(plaintext)], plaintext) {
panic("cipher: invalid buffer overlap")
}
lastCiphertext := ciphertext
if concCipher, ok := c.b.(concurrentBlocks); ok {
batchSize := concCipher.Concurrency() * blockSize
var tweaks = make([]byte, batchSize)
for len(plaintext) >= batchSize {
doubleTweaks(&c.tweak, tweaks, c.isGB)
subtle.XORBytes(ciphertext, plaintext, tweaks)
concCipher.EncryptBlocks(ciphertext, ciphertext)
subtle.XORBytes(ciphertext, ciphertext, tweaks)
plaintext = plaintext[batchSize:]
lastCiphertext = ciphertext[batchSize-blockSize:]
ciphertext = ciphertext[batchSize:]
}
}
for len(plaintext) >= blockSize {
subtle.XORBytes(ciphertext, plaintext, c.tweak[:])
c.b.Encrypt(ciphertext, ciphertext)
subtle.XORBytes(ciphertext, ciphertext, c.tweak[:])
plaintext = plaintext[blockSize:]
lastCiphertext = ciphertext
ciphertext = ciphertext[blockSize:]
mul2(&c.tweak, c.isGB)
}
// is there a final partial block to handle?
if remain := len(plaintext); remain > 0 {
var x [blockSize]byte
//Copy the final plaintext bytes
copy(x[:], plaintext)
//Steal ciphertext to complete the block
copy(x[remain:], lastCiphertext[remain:blockSize])
//Copy the final ciphertext bytes
copy(ciphertext, lastCiphertext[:remain])
//Merge the tweak into the input block
subtle.XORBytes(x[:], x[:], c.tweak[:])
//Encrypt the final block using K1
c.b.Encrypt(x[:], x[:])
//Merge the tweak into the output block
subtle.XORBytes(lastCiphertext, x[:], c.tweak[:])
}
}
func (c *xtsDecrypter) BlockSize() int {
return blockSize
}
// CryptBlocks decrypts a sector of ciphertext and puts the result into plaintext.
// Plaintext and ciphertext must overlap entirely or not at all.
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
func (c *xtsDecrypter) CryptBlocks(plaintext, ciphertext []byte) {
if len(plaintext) < len(ciphertext) {
panic("cipher: plaintext is smaller than ciphertext")
}
if len(ciphertext) < blockSize {
panic("cipher: ciphertext length is smaller than the block size")
}
if alias.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) {
panic("cipher: invalid buffer overlap")
}
if concCipher, ok := c.b.(concurrentBlocks); ok {
batchSize := concCipher.Concurrency() * blockSize
var tweaks = make([]byte, batchSize)
for len(ciphertext) >= batchSize {
doubleTweaks(&c.tweak, tweaks, c.isGB)
subtle.XORBytes(plaintext, ciphertext, tweaks)
concCipher.DecryptBlocks(plaintext, plaintext)
subtle.XORBytes(plaintext, plaintext, tweaks)
plaintext = plaintext[batchSize:]
ciphertext = ciphertext[batchSize:]
}
}
for len(ciphertext) >= 2*blockSize {
subtle.XORBytes(plaintext, ciphertext, c.tweak[:])
c.b.Decrypt(plaintext, plaintext)
subtle.XORBytes(plaintext, plaintext, c.tweak[:])
plaintext = plaintext[blockSize:]
ciphertext = ciphertext[blockSize:]
mul2(&c.tweak, c.isGB)
}
if remain := len(ciphertext); remain >= blockSize {
var x [blockSize]byte
if remain > blockSize {
var tt [blockSize]byte
copy(tt[:], c.tweak[:])
mul2(&tt, c.isGB)
subtle.XORBytes(x[:], ciphertext, tt[:])
c.b.Decrypt(x[:], x[:])
subtle.XORBytes(plaintext, x[:], tt[:])
//Retrieve the length of the final block
remain -= blockSize
//Copy the final ciphertext bytes
copy(x[:], ciphertext[blockSize:])
//Steal ciphertext to complete the block
copy(x[remain:], plaintext[remain:blockSize])
//Copy the final plaintext bytes
copy(plaintext[blockSize:], plaintext)
subtle.XORBytes(x[:], x[:], c.tweak[:])
c.b.Decrypt(x[:], x[:])
subtle.XORBytes(plaintext, x[:], c.tweak[:])
} else {
//The last block contains exactly 128 bits
subtle.XORBytes(plaintext, ciphertext, c.tweak[:])
c.b.Decrypt(plaintext, plaintext)
subtle.XORBytes(plaintext, plaintext, c.tweak[:])
// Maybe there are still ciphertext
mul2(&c.tweak, c.isGB)
}
}
}
// mul2Generic multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
// x¹²⁸ + x⁷ + x² + x + 1.
func mul2Generic(tweak *[blockSize]byte, isGB bool) {
var carryIn byte
if !isGB {
// the coefficient of x⁰ can be obtained by tweak[0] & 1
// the coefficient of x⁷ can be obtained by tweak[0] >> 7
// the coefficient of x¹²⁰ can be obtained by tweak[15] & 1
// the coefficient of x¹²⁷ can be obtained by tweak[15] >> 7
for j := range tweak {
carryOut := tweak[j] >> 7
tweak[j] = (tweak[j] << 1) + carryIn
carryIn = carryOut
}
if carryIn != 0 {
// If we have a carry bit then we need to subtract a multiple
// of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
// By dropping the carry bit, we're subtracting the x^128 term
// so all that remains is to subtract x⁷ + x² + x + 1.
// Subtraction (and addition) in this representation is just
// XOR.
tweak[0] ^= GF128_FDBK // 1<<7 | 1<<2 | 1<<1 | 1
}
} else {
// GB/T 17964-2021,
// the coefficient of x⁰ can be obtained by tweak[0] >> 7
// the coefficient of x⁷ can be obtained by tweak[0] & 1
// the coefficient of x¹²⁰ can be obtained by tweak[15] >> 7
// the coefficient of x¹²⁷ can be obtained by tweak[15] & 1
for j := range tweak {
carryOut := (tweak[j] << 7) & 0x80
tweak[j] = (tweak[j] >> 1) + carryIn
carryIn = carryOut
}
if carryIn != 0 {
tweak[0] ^= 0xE1 // 1<<7 | 1<<6 | 1<<5 | 1
}
}
}

View File

@ -0,0 +1,125 @@
//go:build !purego
#include "textflag.h"
DATA bswapMask<>+0x00(SB)/8, $0x08090a0b0c0d0e0f
DATA bswapMask<>+0x08(SB)/8, $0x0001020304050607
DATA gcmPoly<>+0x00(SB)/8, $0x0000000000000087
DATA gcmPoly<>+0x08(SB)/8, $0x0000000000000000
DATA gbGcmPoly<>+0x00(SB)/8, $0x0000000000000000
DATA gbGcmPoly<>+0x08(SB)/8, $0xe100000000000000
GLOBL bswapMask<>(SB), (NOPTR+RODATA), $16
GLOBL gcmPoly<>(SB), (NOPTR+RODATA), $16
GLOBL gbGcmPoly<>(SB), (NOPTR+RODATA), $16
#define POLY X0
#define BSWAP X1
#define B0 X2
#define T0 X3
#define T1 X4
#define doubleTweak(B0, POLY, T0, T1) \
\ // B0 * 2
PSHUFD $0xff, B0, T0 \
MOVOU B0, T1 \
PSRAL $31, T0 \ // T0 for reduction
PAND POLY, T0 \
PSRLL $31, T1 \
PSLLDQ $4, T1 \
PSLLL $1, B0 \
PXOR T0, B0 \
PXOR T1, B0
#define gbDoubleTweak(B0, BSWAP, POLY, T0, T1) \
PSHUFB BSWAP, B0 \
\ // B0 * 2
MOVOU B0, T0 \
PSHUFD $0, B0, T1 \
PSRLQ $1, B0 \
PSLLQ $63, T0 \
PSRLDQ $8, T0 \
POR T0, B0 \
\ // reduction
PSLLL $31, T1 \
PSRAL $31, T1 \
PAND POLY, T1 \
PXOR T1, B0 \
PSHUFB BSWAP, B0
// func mul2(tweak *[blockSize]byte, isGB bool)
TEXT ·mul2(SB),NOSPLIT,$0
MOVQ tweak+0(FP), DI
MOVB isGB+8(FP), AX
MOVOU (0*16)(DI), B0
CMPB AX, $1
JE gb_alg
MOVOU gcmPoly<>(SB), POLY
doubleTweak(B0, POLY, T0, T1)
MOVOU B0, (0*16)(DI)
RET
gb_alg:
MOVOU bswapMask<>(SB), BSWAP
MOVOU gbGcmPoly<>(SB), POLY
gbDoubleTweak(B0, BSWAP, POLY, T0, T1)
MOVOU B0, (0*16)(DI)
RET
// func doubleTweaks(tweak *[blockSize]byte, tweaks []byte, isGB bool)
TEXT ·doubleTweaks(SB),NOSPLIT,$0
MOVQ tweak+0(FP), DI
MOVQ tweaks+8(FP), AX
MOVQ tweaks_len+16(FP), BX
MOVB isGB+32(FP), CX
MOVOU (0*16)(DI), B0
SHRQ $4, BX
XORQ DX, DX
CMPB CX, $1
JE dt_gb_alg
MOVOU gcmPoly<>(SB), POLY
loop:
MOVOU B0, (0*16)(AX)
LEAQ 16(AX), AX
doubleTweak(B0, POLY, T0, T1)
ADDQ $1, DX
CMPQ DX, BX
JB loop
MOVOU B0, (0*16)(DI)
RET
dt_gb_alg:
MOVOU bswapMask<>(SB), BSWAP
MOVOU gbGcmPoly<>(SB), POLY
gb_loop:
MOVOU B0, (0*16)(AX)
LEAQ 16(AX), AX
gbDoubleTweak(B0, BSWAP, POLY, T0, T1)
ADDQ $1, DX
CMPQ DX, BX
JB gb_loop
MOVOU B0, (0*16)(DI)
RET

View File

@ -0,0 +1,124 @@
//go:build !purego
#include "textflag.h"
#define B0 V0
#define T1 V1
#define T2 V2
#define POLY V3
#define ZERO V4
#define TW R0
#define GB R1
#define I R2
#define doubleTweak(B0, ZERO, POLY, I, T1, T2) \
VMOV B0.D[1], I \
ASR $63, I \
VMOV I, T1.D2 \
VAND POLY.B16, T1.B16, T1.B16 \
\
VUSHR $63, B0.D2, T2.D2 \
VEXT $8, T2.B16, ZERO.B16, T2.B16 \
VSLI $1, B0.D2, T2.D2 \
VEOR T1.B16, T2.B16, B0.B16
#define gbDoubleTweak(B0, ZERO, POLY, I, T1, T2) \
VREV64 B0.B16, B0.B16 \
VEXT $8, B0.B16, B0.B16, B0.B16 \
\
VMOV B0.D[0], I \
LSL $63, I \
ASR $63, I \
VMOV I, T1.D2 \
VAND POLY.B16, T1.B16, T1.B16 \
\
VSHL $63, B0.D2, T2.D2 \
VEXT $8, ZERO.B16, T2.B16, T2.B16 \
VSRI $1, B0.D2, T2.D2 \
VEOR T1.B16, T2.B16, B0.B16 \
\
VEXT $8, B0.B16, B0.B16, B0.B16 \
VREV64 B0.B16, B0.B16
// func mul2(tweak *[blockSize]byte, isGB bool)
TEXT ·mul2(SB),NOSPLIT,$0
MOVD tweak+0(FP), TW
MOVB isGB+8(FP), GB
VLD1 (TW), [B0.B16]
VEOR POLY.B16, POLY.B16, POLY.B16
VEOR ZERO.B16, ZERO.B16, ZERO.B16
CMP $1, GB
BEQ gb_alg
MOVD $0x87, I
VMOV I, POLY.D[0]
doubleTweak(B0, ZERO, POLY, I, T1, T2)
VST1 [B0.B16], (TW)
RET
gb_alg:
MOVD $0xE1, I
LSL $56, I
VMOV I, POLY.D[1]
gbDoubleTweak(B0, ZERO, POLY, I, T1, T2)
VST1 [B0.B16], (TW)
RET
// func doubleTweaks(tweak *[blockSize]byte, tweaks []byte, isGB bool)
TEXT ·doubleTweaks(SB),NOSPLIT,$0
MOVD tweak+0(FP), TW
MOVD tweaks+8(FP), R3
MOVD tweaks_len+16(FP), R4
MOVB isGB+32(FP), GB
LSR $4, R4
EOR R5, R5
VEOR POLY.B16, POLY.B16, POLY.B16
VEOR ZERO.B16, ZERO.B16, ZERO.B16
VLD1 (TW), [B0.B16]
CMP $1, GB
BEQ dt_gb_alg
MOVD $0x87, I
VMOV I, POLY.D[0]
loop:
VST1.P [B0.B16], 16(R3)
doubleTweak(B0, ZERO, POLY, I, T1, T2)
ADD $1, R5
CMP R4, R5
BNE loop
VST1 [B0.B16], (TW)
RET
dt_gb_alg:
MOVD $0xE1, I
LSL $56, I
VMOV I, POLY.D[1]
gb_loop:
VST1.P [B0.B16], 16(R3)
gbDoubleTweak(B0, ZERO, POLY, I, T1, T2)
ADD $1, R5
CMP R4, R5
BNE gb_loop
VST1 [B0.B16], (TW)
RET

View File

@ -0,0 +1,9 @@
//go:build (amd64 || arm64 || s390x || ppc64 || ppc64le) && !purego
package xts
//go:noescape
func mul2(tweak *[blockSize]byte, isGB bool)
//go:noescape
func doubleTweaks(tweak *[blockSize]byte, tweaks []byte, isGB bool)

View File

@ -0,0 +1,105 @@
//go:build (amd64 || arm64 || s390x || ppc64 || ppc64le) && !purego
package xts
import (
"bytes"
"crypto/rand"
"encoding/hex"
"io"
"testing"
)
var testTweakVector = []string{
"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF",
"66e94bd4ef8a2c3b884cfa59ca342b2e",
"3f803bcd0d7fd2b37558419f59d5cda6",
"6dcfba212f5d82bf525ee9793cfa505a",
"c172964cd58be2b8d8e09d9c5e9cfe36",
"1a267577a90caad6ae988e22714a2b8b",
"33fab707493702e77ff8d66ba9e6c6fe",
"23fb188b0f87f6ee2ec0803a99771341",
"e8de0a4188b7efbc1ac3979eb906cf36",
}
func testDoubleTweak(t *testing.T, isGB bool) {
for _, tk := range testTweakVector {
tweak, _ := hex.DecodeString(tk)
var t1, t2 [16]byte
copy(t1[:], tweak)
copy(t2[:], tweak)
mul2(&t1, isGB)
mul2Generic(&t2, isGB)
if !bytes.Equal(t1[:], t2[:]) {
t.Errorf("tweak %v, expected %x, got %x", tk, t2[:], t1[:])
}
}
}
func TestDoubleTweak(t *testing.T) {
testDoubleTweak(t, false)
}
func TestDoubleTweakGB(t *testing.T) {
testDoubleTweak(t, true)
}
func testDoubleTweakRandomly(t *testing.T, isGB bool) {
var tweak, t1, t2 [16]byte
io.ReadFull(rand.Reader, tweak[:])
copy(t1[:], tweak[:])
copy(t2[:], tweak[:])
mul2(&t1, isGB)
mul2Generic(&t2, isGB)
if !bytes.Equal(t1[:], t2[:]) {
t.Errorf("tweak %x, expected %x, got %x", tweak[:], t2[:], t1[:])
}
}
func TestDoubleTweakRandomly(t *testing.T) {
for i := 0; i < 10; i++ {
testDoubleTweakRandomly(t, false)
}
}
func TestDoubleTweakGBRandomly(t *testing.T) {
for i := 0; i < 10; i++ {
testDoubleTweakRandomly(t, true)
}
}
func testDoubleTweaks(t *testing.T, isGB bool) {
for _, tk := range testTweakVector {
tweak, _ := hex.DecodeString(tk)
var t1, t2 [16]byte
var t11, t12 [128]byte
copy(t1[:], tweak)
copy(t2[:], tweak)
for i := 0; i < 8; i++ {
copy(t12[16*i:], t2[:])
mul2Generic(&t2, isGB)
}
doubleTweaks(&t1, t11[:], isGB)
if !bytes.Equal(t1[:], t2[:]) {
t.Errorf("1 tweak %v, expected %x, got %x", tk, t2[:], t1[:])
}
if !bytes.Equal(t11[:], t12[:]) {
t.Errorf("2 tweak %v, expected %x, got %x", tk, t12[:], t11[:])
}
}
}
func TestDoubleTweaks(t *testing.T) {
testDoubleTweaks(t, false)
}
func TestDoubleTweaksGB(t *testing.T) {
testDoubleTweaks(t, true)
}

View File

@ -0,0 +1,15 @@
//go:build purego || !(amd64 || arm64 || s390x || ppc64 || ppc64le)
package xts
func mul2(tweak *[blockSize]byte, isGB bool) {
mul2Generic(tweak, isGB)
}
func doubleTweaks(tweak *[blockSize]byte, tweaks []byte, isGB bool) {
count := len(tweaks) >> 4
for i := range count {
copy(tweaks[blockSize*i:], tweak[:])
mul2(tweak, isGB)
}
}

View File

@ -0,0 +1,166 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//go:build (ppc64 || ppc64le) && !purego
#include "textflag.h"
DATA xtsMask<>+0x00(SB)/8, $0x0f0e0d0c0b0a0908 // byte swap BE -> LE
DATA xtsMask<>+0x08(SB)/8, $0x0706050403020100
DATA xtsMask<>+0x10(SB)/8, $0x0000000000000000
DATA xtsMask<>+0x18(SB)/8, $0x0000000000000087
DATA xtsMask<>+0x20(SB)/8, $0xe100000000000000
DATA xtsMask<>+0x28(SB)/8, $0x0000000000000000
GLOBL xtsMask<>(SB), (NOPTR+RODATA), $48
#define ESPERM V21 // Endian swapping permute into BE
#define POLY V0
#define B0 V1
#define T0 V2
#define T1 V3
#define CPOOL R7
#define doubleTweak(B0, POLY, T0, T1) \
\ // Multiply by 2
VSPLTB $0, B0, T0 \
VSPLTISB $7, T1 \
VSRAB T0, T1, T0 \
VAND POLY, T0, T0 \// T0 for reduction
\
VSPLTISB $1, T1 \
VSL B0, T1, T1 \
VXOR T0, T1, B0
#define gbDoubleTweak(B0, POLY, T0, T1) \
VSPLTB $15, B0, T0 \
VSPLTISB $7, T1 \
VSLB T0, T1, T0 \
VSRAB T0, T1, T0 \
VAND POLY, T0, T0 \ // T0 for reduction
VSPLTISB $1, T1 \
VSR B0, T1, B0 \
VXOR T0, B0, B0
// func mul2(tweak *[blockSize]byte, isGB bool)
TEXT ·mul2(SB),NOSPLIT,$0
MOVD tweak+0(FP), R3
MOVBZ isGB+8(FP), R4
MOVD $xtsMask<>(SB), CPOOL
CMPW R4, $1
BEQ gb_alg
// Load polynomial for reduction
MOVD $16, R5
LXVD2X (CPOOL)(R5), POLY
// Load tweak
LXVD2X (R3), B0
#ifdef GOARCH_ppc64le
XXPERMDI B0, B0, $2, B0
doubleTweak(B0, POLY, T0, T1)
XXPERMDI B0, B0, $2, B0
#else
LXVD2X (CPOOL), ESPERM
VPERM B0, B0, ESPERM, B0
doubleTweak(B0, POLY, T0, T1)
VPERM B0, B0, ESPERM, B0
#endif
STXVD2X B0, (R3)
RET
gb_alg:
// Load polynomial for reduction
MOVD $32, R5
LXVD2X (CPOOL)(R5), POLY
// Load tweak
LXVD2X (R3), B0
#ifdef GOARCH_ppc64le
LVX (CPOOL), ESPERM
VPERM B0, B0, ESPERM, B0
gbDoubleTweak(B0, POLY, T0, T1)
VPERM B0, B0, ESPERM, B0
#else
gbDoubleTweak(B0, POLY, T0, T1)
#endif
STXVD2X B0, (R3)
RET
// func doubleTweaks(tweak *[blockSize]byte, tweaks []byte, isGB bool)
TEXT ·doubleTweaks(SB),NOSPLIT,$0
MOVD tweak+0(FP), R3
MOVD tweaks+8(FP), R4
MOVD tweaks_len+16(FP), R5
MOVBZ isGB+32(FP), R6
MOVD $xtsMask<>(SB), CPOOL
// Load tweak
LXVD2X (R3), B0
CMPW R6, $1
BEQ gb_alg
SRD $4, R5
MOVD R5, CTR
#ifndef GOARCH_ppc64le
LXVD2X (CPOOL), ESPERM
#endif
// Load polynomial for reduction
MOVD $16, R5
LXVD2X (CPOOL)(R5), POLY
loop:
STXVD2X B0, (R4)
ADD $16, R4
#ifdef GOARCH_ppc64le
XXPERMDI B0, B0, $2, B0
doubleTweak(B0, POLY, T0, T1)
XXPERMDI B0, B0, $2, B0
#else
VPERM B0, B0, ESPERM, B0
doubleTweak(B0, POLY, T0, T1)
VPERM B0, B0, ESPERM, B0
#endif
BDNZ loop
STXVD2X B0, (R3)
RET
gb_alg:
SRD $4, R5
MOVD R5, CTR
// Load polynomial for reduction
MOVD $32, R5
LXVD2X (CPOOL)(R5), POLY
#ifdef GOARCH_ppc64le
LVX (CPOOL), ESPERM
#endif
gbLoop:
STXVD2X B0, (R4)
ADD $16, R4
#ifdef GOARCH_ppc64le
VPERM B0, B0, ESPERM, B0
gbDoubleTweak(B0, POLY, T0, T1)
VPERM B0, B0, ESPERM, B0
#else
gbDoubleTweak(B0, POLY, T0, T1)
#endif
BDNZ gbLoop
STXVD2X B0, (R3)
RET

View File

@ -0,0 +1,121 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//go:build !purego
#include "textflag.h"
DATA xtsMask<>+0x00(SB)/8, $0x0f0e0d0c0b0a0908 // byte swap BE -> LE
DATA xtsMask<>+0x08(SB)/8, $0x0706050403020100
GLOBL xtsMask<>(SB), (NOPTR+RODATA), $16
#define BSWAP V0
#define POLY V1
#define B0 V2
#define T0 V3
#define T1 V4
#define CPOOL R3
#define doubleTweak(B0, BSWAP, POLY, T0, T1) \
VPERM B0, B0, BSWAP, B0 \// BE -> LE
\ // Multiply by 2
VESRAF $31, B0, T0 \
VREPF $0, T0, T0 \
VN POLY, T0, T0 \ // T0 for reduction
VREPIB $1, T1 \
VSL T1, B0, T1 \
VX T1, T0, B0 \
\
VPERM B0, B0, BSWAP, B0
#define gbDoubleTweak(B0, POLY, T0, T1) \
VESLF $31, B0, T0 \
VESRAF $31, T0, T0 \
VREPF $3, T0, T0 \
VN POLY, T0, T0 \ // T0 for reduction
\
VREPIB $1, T1 \
VSRL T1, B0, T1 \
VX T1, T0, B0
// func mul2(tweak *[blockSize]byte, isGB bool)
TEXT ·mul2(SB),NOSPLIT,$0
MOVD tweak+0(FP), R1
MOVB isGB+8(FP), R2
CMPBEQ R2, $1, gb_alg
MOVD $xtsMask<>+0x00(SB), CPOOL
VL (CPOOL), BSWAP
// Load polynomial for reduction
VZERO POLY
VLEIB $15, $0x87, POLY
// Load tweak
VL 0(R1), B0
doubleTweak(B0, BSWAP, POLY, T0, T1)
VST B0, 0(R1)
RET
gb_alg:
// Load polynomial for reduction
VZERO POLY
VLEIB $0, $0xe1, POLY
// Load tweak
VL 0(R1), B0
gbDoubleTweak(B0, POLY, T0, T1)
VST B0, 0(R1)
RET
// func doubleTweaks(tweak *[blockSize]byte, tweaks []byte, isGB bool)
TEXT ·doubleTweaks(SB),NOSPLIT,$0
MOVD tweak+0(FP), R1
MOVD tweaks+8(FP), R2
MOVD tweaks_len+16(FP), R3
MOVB isGB+32(FP), R4
AND $-16, R3
LAY (R2)(R3*1), R5
VL 0(R1), B0
CMPBEQ R4, $1, gb_alg
MOVD $xtsMask<>+0x00(SB), CPOOL
VL (CPOOL), BSWAP
// Load polynomial for reduction
VZERO POLY
VLEIB $15, $0x87, POLY
loop:
VST B0, 0(R2)
doubleTweak(B0, BSWAP, POLY, T0, T1)
LA 16(R2), R2
CMPBLT R2, R5, loop
VST B0, 0(R1)
RET
gb_alg:
// Load polynomial for reduction
VZERO POLY
VLEIB $0, $0xe1, POLY
gb_alg_loop:
VST B0, 0(R2)
gbDoubleTweak(B0, POLY, T0, T1)
LA 16(R2), R2
CMPBLT R2, R5, gb_alg_loop
VST B0, 0(R1)
RET

Some files were not shown because too many files have changed in this diff Show More