Repository: ZZMarquis/gm
Branch: master
Commit: 950ad0926746
Files: 25
Total size: 147.4 KB
Directory structure:
gitextract_meawgwxy/
├── .github/
│ └── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── cryptobyte/
│ ├── README
│ ├── asn1/
│ │ └── asn1.go
│ ├── asn1.go
│ ├── builder.go
│ └── string.go
├── go.mod
├── sm2/
│ ├── cert/
│ │ ├── gmx509.go
│ │ └── gmx509_test.go
│ ├── keyexchange.go
│ ├── keyexchange_test.go
│ ├── sm2.go
│ ├── sm2_loop_test.go
│ └── sm2_test.go
├── sm3/
│ ├── sm3.go
│ └── sm3_test.go
├── sm4/
│ ├── sm4.go
│ └── sm4_test.go
└── util/
├── bigint.go
├── bigint_test.go
├── ec.go
└── padding.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://weibo.com/5978668016/KDzUy5mOq
================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# gm
================================================
FILE: cryptobyte/README
================================================
这个包下的代码全部copy自SDK中的golang_org/x/crypto/cryptobyte包,这个包不对应用开放,所以只好全部copy过来
================================================
FILE: cryptobyte/asn1/asn1.go
================================================
// Copyright 2017 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 asn1 contains supporting types for parsing and building ASN.1
// messages with the cryptobyte package.
package asn1
// Tag represents an ASN.1 identifier octet, consisting of a tag number
// (indicating a type) and class (such as context-specific or constructed).
//
// Methods in the cryptobyte package only support the low-tag-number form, i.e.
// a single identifier octet with bits 7-8 encoding the class and bits 1-6
// encoding the tag number.
type Tag uint8
const (
classConstructed = 0x20
classContextSpecific = 0x80
)
// Constructed returns t with the constructed class bit set.
func (t Tag) Constructed() Tag { return t | classConstructed }
// ContextSpecific returns t with the context-specific class bit set.
func (t Tag) ContextSpecific() Tag { return t | classContextSpecific }
// The following is a list of standard tag and class combinations.
const (
BOOLEAN = Tag(1)
INTEGER = Tag(2)
BIT_STRING = Tag(3)
OCTET_STRING = Tag(4)
NULL = Tag(5)
OBJECT_IDENTIFIER = Tag(6)
ENUM = Tag(10)
UTF8String = Tag(12)
SEQUENCE = Tag(16 | classConstructed)
SET = Tag(17 | classConstructed)
PrintableString = Tag(19)
T61String = Tag(20)
IA5String = Tag(22)
UTCTime = Tag(23)
GeneralizedTime = Tag(24)
GeneralString = Tag(27)
)
================================================
FILE: cryptobyte/asn1.go
================================================
// Copyright 2017 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 cryptobyte
import (
encoding_asn1 "encoding/asn1"
"fmt"
"math/big"
"reflect"
"time"
"github.com/ZZMarquis/gm/cryptobyte/asn1"
)
// This file contains ASN.1-related methods for String and Builder.
// Builder
// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER.
func (b *Builder) AddASN1Int64(v int64) {
b.addASN1Signed(asn1.INTEGER, v)
}
// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION.
func (b *Builder) AddASN1Enum(v int64) {
b.addASN1Signed(asn1.ENUM, v)
}
func (b *Builder) addASN1Signed(tag asn1.Tag, v int64) {
b.AddASN1(tag, func(c *Builder) {
length := 1
for i := v; i >= 0x80 || i < -0x80; i >>= 8 {
length++
}
for ; length > 0; length-- {
i := v >> uint((length-1)*8) & 0xff
c.AddUint8(uint8(i))
}
})
}
// AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER.
func (b *Builder) AddASN1Uint64(v uint64) {
b.AddASN1(asn1.INTEGER, func(c *Builder) {
length := 1
for i := v; i >= 0x80; i >>= 8 {
length++
}
for ; length > 0; length-- {
i := v >> uint((length-1)*8) & 0xff
c.AddUint8(uint8(i))
}
})
}
// AddASN1BigInt appends a DER-encoded ASN.1 INTEGER.
func (b *Builder) AddASN1BigInt(n *big.Int) {
if b.err != nil {
return
}
b.AddASN1(asn1.INTEGER, func(c *Builder) {
if n.Sign() < 0 {
// A negative number has to be converted to two's-complement form. So we
// invert and subtract 1. If the most-significant-bit isn't set then
// we'll need to pad the beginning with 0xff in order to keep the number
// negative.
nMinus1 := new(big.Int).Neg(n)
nMinus1.Sub(nMinus1, bigOne)
bytes := nMinus1.Bytes()
for i := range bytes {
bytes[i] ^= 0xff
}
if bytes[0]&0x80 == 0 {
c.add(0xff)
}
c.add(bytes...)
} else if n.Sign() == 0 {
c.add(0)
} else {
bytes := n.Bytes()
if bytes[0]&0x80 != 0 {
c.add(0)
}
c.add(bytes...)
}
})
}
// AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING.
func (b *Builder) AddASN1OctetString(bytes []byte) {
b.AddASN1(asn1.OCTET_STRING, func(c *Builder) {
c.AddBytes(bytes)
})
}
const generalizedTimeFormatStr = "20060102150405Z0700"
// AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME.
func (b *Builder) AddASN1GeneralizedTime(t time.Time) {
if t.Year() < 0 || t.Year() > 9999 {
b.err = fmt.Errorf("cryptobyte: cannot represent %v as a GeneralizedTime", t)
return
}
b.AddASN1(asn1.GeneralizedTime, func(c *Builder) {
c.AddBytes([]byte(t.Format(generalizedTimeFormatStr)))
})
}
// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING. This does not
// support BIT STRINGs that are not a whole number of bytes.
func (b *Builder) AddASN1BitString(data []byte) {
b.AddASN1(asn1.BIT_STRING, func(b *Builder) {
b.AddUint8(0)
b.AddBytes(data)
})
}
func (b *Builder) addBase128Int(n int64) {
var length int
if n == 0 {
length = 1
} else {
for i := n; i > 0; i >>= 7 {
length++
}
}
for i := length - 1; i >= 0; i-- {
o := byte(n >> uint(i*7))
o &= 0x7f
if i != 0 {
o |= 0x80
}
b.add(o)
}
}
func isValidOID(oid encoding_asn1.ObjectIdentifier) bool {
if len(oid) < 2 {
return false
}
if oid[0] > 2 || (oid[0] <= 1 && oid[1] >= 40) {
return false
}
for _, v := range oid {
if v < 0 {
return false
}
}
return true
}
func (b *Builder) AddASN1ObjectIdentifier(oid encoding_asn1.ObjectIdentifier) {
b.AddASN1(asn1.OBJECT_IDENTIFIER, func(b *Builder) {
if !isValidOID(oid) {
b.err = fmt.Errorf("cryptobyte: invalid OID: %v", oid)
return
}
b.addBase128Int(int64(oid[0])*40 + int64(oid[1]))
for _, v := range oid[2:] {
b.addBase128Int(int64(v))
}
})
}
func (b *Builder) AddASN1Boolean(v bool) {
b.AddASN1(asn1.BOOLEAN, func(b *Builder) {
if v {
b.AddUint8(0xff)
} else {
b.AddUint8(0)
}
})
}
func (b *Builder) AddASN1NULL() {
b.add(uint8(asn1.NULL), 0)
}
// MarshalASN1 calls encoding_asn1.Marshal on its input and appends the result if
// successful or records an error if one occurred.
func (b *Builder) MarshalASN1(v interface{}) {
// NOTE(martinkr): This is somewhat of a hack to allow propagation of
// encoding_asn1.Marshal errors into Builder.err. N.B. if you call MarshalASN1 with a
// value embedded into a struct, its tag information is lost.
if b.err != nil {
return
}
bytes, err := encoding_asn1.Marshal(v)
if err != nil {
b.err = err
return
}
b.AddBytes(bytes)
}
// AddASN1 appends an ASN.1 object. The object is prefixed with the given tag.
// Tags greater than 30 are not supported and result in an error (i.e.
// low-tag-number form only). The child builder passed to the
// BuilderContinuation can be used to build the content of the ASN.1 object.
func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) {
if b.err != nil {
return
}
// Identifiers with the low five bits set indicate high-tag-number format
// (two or more octets), which we don't support.
if tag&0x1f == 0x1f {
b.err = fmt.Errorf("cryptobyte: high-tag number identifier octects not supported: 0x%x", tag)
return
}
b.AddUint8(uint8(tag))
b.addLengthPrefixed(1, true, f)
}
// String
func (s *String) ReadASN1Boolean(out *bool) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.INTEGER) || len(bytes) != 1 {
return false
}
switch bytes[0] {
case 0:
*out = false
case 0xff:
*out = true
default:
return false
}
return true
}
var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem()
// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does
// not point to an integer or to a big.Int, it panics. It returns true on
// success and false on error.
func (s *String) ReadASN1Integer(out interface{}) bool {
if reflect.TypeOf(out).Kind() != reflect.Ptr {
panic("out is not a pointer")
}
switch reflect.ValueOf(out).Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
var i int64
if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) {
return false
}
reflect.ValueOf(out).Elem().SetInt(i)
return true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
var u uint64
if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) {
return false
}
reflect.ValueOf(out).Elem().SetUint(u)
return true
case reflect.Struct:
if reflect.TypeOf(out).Elem() == bigIntType {
return s.readASN1BigInt(out.(*big.Int))
}
}
panic("out does not point to an integer type")
}
func checkASN1Integer(bytes []byte) bool {
if len(bytes) == 0 {
// An INTEGER is encoded with at least one octet.
return false
}
if len(bytes) == 1 {
return true
}
if bytes[0] == 0 && bytes[1]&0x80 == 0 || bytes[0] == 0xff && bytes[1]&0x80 == 0x80 {
// Value is not minimally encoded.
return false
}
return true
}
var bigOne = big.NewInt(1)
func (s *String) readASN1BigInt(out *big.Int) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) {
return false
}
if bytes[0]&0x80 == 0x80 {
// Negative number.
neg := make([]byte, len(bytes))
for i, b := range bytes {
neg[i] = ^b
}
out.SetBytes(neg)
out.Add(out, bigOne)
out.Neg(out)
} else {
out.SetBytes(bytes)
}
return true
}
func (s *String) readASN1Int64(out *int64) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) {
return false
}
return true
}
func asn1Signed(out *int64, n []byte) bool {
length := len(n)
if length > 8 {
return false
}
for i := 0; i < length; i++ {
*out <<= 8
*out |= int64(n[i])
}
// Shift up and down in order to sign extend the result.
*out <<= 64 - uint8(length)*8
*out >>= 64 - uint8(length)*8
return true
}
func (s *String) readASN1Uint64(out *uint64) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Unsigned(out, bytes) {
return false
}
return true
}
func asn1Unsigned(out *uint64, n []byte) bool {
length := len(n)
if length > 9 || length == 9 && n[0] != 0 {
// Too large for uint64.
return false
}
if n[0]&0x80 != 0 {
// Negative number.
return false
}
for i := 0; i < length; i++ {
*out <<= 8
*out |= uint64(n[i])
}
return true
}
// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It returns
// true on success and false on error.
func (s *String) ReadASN1Enum(out *int) bool {
var bytes String
var i int64
if !s.ReadASN1(&bytes, asn1.ENUM) || !checkASN1Integer(bytes) || !asn1Signed(&i, bytes) {
return false
}
if int64(int(i)) != i {
return false
}
*out = int(i)
return true
}
func (s *String) readBase128Int(out *int) bool {
ret := 0
for i := 0; len(*s) > 0; i++ {
if i == 4 {
return false
}
ret <<= 7
b := s.read(1)[0]
ret |= int(b & 0x7f)
if b&0x80 == 0 {
*out = ret
return true
}
}
return false // truncated
}
// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and
// advances. It returns true on success and false on error.
func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 {
return false
}
// In the worst case, we get two elements from the first byte (which is
// encoded differently) and then every varint is a single byte long.
components := make([]int, len(bytes)+1)
// The first varint is 40*value1 + value2:
// According to this packing, value1 can take the values 0, 1 and 2 only.
// When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
// then there are no restrictions on value2.
var v int
if !bytes.readBase128Int(&v) {
return false
}
if v < 80 {
components[0] = v / 40
components[1] = v % 40
} else {
components[0] = 2
components[1] = v - 80
}
i := 2
for ; len(bytes) > 0; i++ {
if !bytes.readBase128Int(&v) {
return false
}
components[i] = v
}
*out = components[:i]
return true
}
// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and
// advances. It returns true on success and false on error.
func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.GeneralizedTime) {
return false
}
t := string(bytes)
res, err := time.Parse(generalizedTimeFormatStr, t)
if err != nil {
return false
}
if serialized := res.Format(generalizedTimeFormatStr); serialized != t {
return false
}
*out = res
return true
}
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It
// returns true on success and false on error.
func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 {
return false
}
paddingBits := uint8(bytes[0])
bytes = bytes[1:]
if paddingBits > 7 ||
len(bytes) == 0 && paddingBits != 0 ||
len(bytes) > 0 && bytes[len(bytes)-1]&(1<<paddingBits-1) != 0 {
return false
}
out.BitLength = len(bytes)*8 - int(paddingBits)
out.Bytes = bytes
return true
}
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It is
// an error if the BIT STRING is not a whole number of bytes. This function
// returns true on success and false on error.
func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool {
var bytes String
if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 {
return false
}
paddingBits := uint8(bytes[0])
if paddingBits != 0 {
return false
}
*out = bytes[1:]
return true
}
// ReadASN1Bytes reads the contents of a DER-encoded ASN.1 element (not including
// tag and length bytes) into out, and advances. The element must match the
// given tag. It returns true on success and false on error.
func (s *String) ReadASN1Bytes(out *[]byte, tag asn1.Tag) bool {
return s.ReadASN1((*String)(out), tag)
}
// ReadASN1 reads the contents of a DER-encoded ASN.1 element (not including
// tag and length bytes) into out, and advances. The element must match the
// given tag. It returns true on success and false on error.
//
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadASN1(out *String, tag asn1.Tag) bool {
var t asn1.Tag
if !s.ReadAnyASN1(out, &t) || t != tag {
return false
}
return true
}
// ReadASN1Element reads the contents of a DER-encoded ASN.1 element (including
// tag and length bytes) into out, and advances. The element must match the
// given tag. It returns true on success and false on error.
//
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool {
var t asn1.Tag
if !s.ReadAnyASN1Element(out, &t) || t != tag {
return false
}
return true
}
// ReadAnyASN1 reads the contents of a DER-encoded ASN.1 element (not including
// tag and length bytes) into out, sets outTag to its tag, and advances. It
// returns true on success and false on error.
//
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadAnyASN1(out *String, outTag *asn1.Tag) bool {
return s.readASN1(out, outTag, true /* skip header */)
}
// ReadAnyASN1Element reads the contents of a DER-encoded ASN.1 element
// (including tag and length bytes) into out, sets outTag to is tag, and
// advances. It returns true on success and false on error.
//
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadAnyASN1Element(out *String, outTag *asn1.Tag) bool {
return s.readASN1(out, outTag, false /* include header */)
}
// PeekASN1Tag returns true if the next ASN.1 value on the string starts with
// the given tag.
func (s String) PeekASN1Tag(tag asn1.Tag) bool {
if len(s) == 0 {
return false
}
return asn1.Tag(s[0]) == tag
}
// SkipASN1 reads and discards an ASN.1 element with the given tag.
func (s *String) SkipASN1(tag asn1.Tag) bool {
var unused String
return s.ReadASN1(&unused, tag)
}
// ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.1
// element (not including tag and length bytes) tagged with the given tag into
// out. It stores whether an element with the tag was found in outPresent,
// unless outPresent is nil. It returns true on success and false on error.
func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn1.Tag) bool {
present := s.PeekASN1Tag(tag)
if outPresent != nil {
*outPresent = present
}
if present && !s.ReadASN1(out, tag) {
return false
}
return true
}
// SkipOptionalASN1 advances s over an ASN.1 element with the given tag, or
// else leaves s unchanged.
func (s *String) SkipOptionalASN1(tag asn1.Tag) bool {
if !s.PeekASN1Tag(tag) {
return true
}
var unused String
return s.ReadASN1(&unused, tag)
}
// ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER
// explicitly tagged with tag into out and advances. If no element with a
// matching tag is present, it writes defaultValue into out instead. If out
// does not point to an integer or to a big.Int, it panics. It returns true on
// success and false on error.
func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultValue interface{}) bool {
if reflect.TypeOf(out).Kind() != reflect.Ptr {
panic("out is not a pointer")
}
var present bool
var i String
if !s.ReadOptionalASN1(&i, &present, tag) {
return false
}
if !present {
switch reflect.ValueOf(out).Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(defaultValue))
case reflect.Struct:
if reflect.TypeOf(out).Elem() != bigIntType {
panic("invalid integer type")
}
if reflect.TypeOf(defaultValue).Kind() != reflect.Ptr ||
reflect.TypeOf(defaultValue).Elem() != bigIntType {
panic("out points to big.Int, but defaultValue does not")
}
out.(*big.Int).Set(defaultValue.(*big.Int))
default:
panic("invalid integer type")
}
return true
}
if !i.ReadASN1Integer(out) || !i.Empty() {
return false
}
return true
}
// ReadOptionalASN1OctetString attempts to read an optional ASN.1 OCTET STRING
// explicitly tagged with tag into out and advances. If no element with a
// matching tag is present, it writes defaultValue into out instead. It returns
// true on success and false on error.
func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag asn1.Tag) bool {
var present bool
var child String
if !s.ReadOptionalASN1(&child, &present, tag) {
return false
}
if outPresent != nil {
*outPresent = present
}
if present {
var oct String
if !child.ReadASN1(&oct, asn1.OCTET_STRING) || !child.Empty() {
return false
}
*out = oct
} else {
*out = nil
}
return true
}
// ReadOptionalASN1Boolean sets *out to the value of the next ASN.1 BOOLEAN or,
// if the next bytes are not an ASN.1 BOOLEAN, to the value of defaultValue.
func (s *String) ReadOptionalASN1Boolean(out *bool, defaultValue bool) bool {
var present bool
var child String
if !s.ReadOptionalASN1(&child, &present, asn1.BOOLEAN) {
return false
}
if !present {
*out = defaultValue
return true
}
return s.ReadASN1Boolean(out)
}
func (s *String) readASN1(out *String, outTag *asn1.Tag, skipHeader bool) bool {
if len(*s) < 2 {
return false
}
tag, lenByte := (*s)[0], (*s)[1]
if tag&0x1f == 0x1f {
// ITU-T X.690 section 8.1.2
//
// An identifier octet with a tag part of 0x1f indicates a high-tag-number
// form identifier with two or more octets. We only support tags less than
// 31 (i.e. low-tag-number form, single octet identifier).
return false
}
if outTag != nil {
*outTag = asn1.Tag(tag)
}
// ITU-T X.690 section 8.1.3
//
// Bit 8 of the first length byte indicates whether the length is short- or
// long-form.
var length, headerLen uint32 // length includes headerLen
if lenByte&0x80 == 0 {
// Short-form length (section 8.1.3.4), encoded in bits 1-7.
length = uint32(lenByte) + 2
headerLen = 2
} else {
// Long-form length (section 8.1.3.5). Bits 1-7 encode the number of octets
// used to encode the length.
lenLen := lenByte & 0x7f
var len32 uint32
if lenLen == 0 || lenLen > 4 || len(*s) < int(2+lenLen) {
return false
}
lenBytes := String((*s)[2 : 2+lenLen])
if !lenBytes.readUnsigned(&len32, int(lenLen)) {
return false
}
// ITU-T X.690 section 10.1 (DER length forms) requires encoding the length
// with the minimum number of octets.
if len32 < 128 {
// Length should have used short-form encoding.
return false
}
if len32>>((lenLen-1)*8) == 0 {
// Leading octet is 0. Length should have been at least one byte shorter.
return false
}
headerLen = 2 + uint32(lenLen)
if headerLen+len32 < len32 {
// Overflow.
return false
}
length = headerLen + len32
}
if uint32(int(length)) != length || !s.ReadBytes((*[]byte)(out), int(length)) {
return false
}
if skipHeader && !out.Skip(int(headerLen)) {
panic("cryptobyte: internal error")
}
return true
}
================================================
FILE: cryptobyte/builder.go
================================================
// Copyright 2017 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 cryptobyte
import (
"errors"
"fmt"
)
// A Builder builds byte strings from fixed-length and length-prefixed values.
// Builders either allocate space as needed, or are ‘fixed’, which means that
// they write into a given buffer and produce an error if it's exhausted.
//
// The zero value is a usable Builder that allocates space as needed.
//
// Simple values are marshaled and appended to a Builder using methods on the
// Builder. Length-prefixed values are marshaled by providing a
// BuilderContinuation, which is a function that writes the inner contents of
// the value to a given Builder. See the documentation for BuilderContinuation
// for details.
type Builder struct {
err error
result []byte
fixedSize bool
child *Builder
offset int
pendingLenLen int
pendingIsASN1 bool
inContinuation *bool
}
// NewBuilder creates a Builder that appends its output to the given buffer.
// Like append(), the slice will be reallocated if its capacity is exceeded.
// Use Bytes to get the final buffer.
func NewBuilder(buffer []byte) *Builder {
return &Builder{
result: buffer,
}
}
// NewFixedBuilder creates a Builder that appends its output into the given
// buffer. This builder does not reallocate the output buffer. Writes that
// would exceed the buffer's capacity are treated as an error.
func NewFixedBuilder(buffer []byte) *Builder {
return &Builder{
result: buffer,
fixedSize: true,
}
}
// Bytes returns the bytes written by the builder or an error if one has
// occurred during during building.
func (b *Builder) Bytes() ([]byte, error) {
if b.err != nil {
return nil, b.err
}
return b.result[b.offset:], nil
}
// BytesOrPanic returns the bytes written by the builder or panics if an error
// has occurred during building.
func (b *Builder) BytesOrPanic() []byte {
if b.err != nil {
panic(b.err)
}
return b.result[b.offset:]
}
// AddUint8 appends an 8-bit value to the byte string.
func (b *Builder) AddUint8(v uint8) {
b.add(byte(v))
}
// AddUint16 appends a big-endian, 16-bit value to the byte string.
func (b *Builder) AddUint16(v uint16) {
b.add(byte(v>>8), byte(v))
}
// AddUint24 appends a big-endian, 24-bit value to the byte string. The highest
// byte of the 32-bit input value is silently truncated.
func (b *Builder) AddUint24(v uint32) {
b.add(byte(v>>16), byte(v>>8), byte(v))
}
// AddUint32 appends a big-endian, 32-bit value to the byte string.
func (b *Builder) AddUint32(v uint32) {
b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// AddBytes appends a sequence of bytes to the byte string.
func (b *Builder) AddBytes(v []byte) {
b.add(v...)
}
// BuilderContinuation is continuation-passing interface for building
// length-prefixed byte sequences. Builder methods for length-prefixed
// sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation
// supplied to them. The child builder passed to the continuation can be used
// to build the content of the length-prefixed sequence. For example:
//
// parent := cryptobyte.NewBuilder()
// parent.AddUint8LengthPrefixed(func (child *Builder) {
// child.AddUint8(42)
// child.AddUint8LengthPrefixed(func (grandchild *Builder) {
// grandchild.AddUint8(5)
// })
// })
//
// It is an error to write more bytes to the child than allowed by the reserved
// length prefix. After the continuation returns, the child must be considered
// invalid, i.e. users must not store any copies or references of the child
// that outlive the continuation.
//
// If the continuation panics with a value of type BuildError then the inner
// error will be returned as the error from Bytes. If the child panics
// otherwise then Bytes will repanic with the same value.
type BuilderContinuation func(child *Builder)
// BuildError wraps an error. If a BuilderContinuation panics with this value,
// the panic will be recovered and the inner error will be returned from
// Builder.Bytes.
type BuildError struct {
Err error
}
// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
b.addLengthPrefixed(1, false, f)
}
// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
b.addLengthPrefixed(2, false, f)
}
// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
b.addLengthPrefixed(3, false, f)
}
// AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence.
func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) {
b.addLengthPrefixed(4, false, f)
}
func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) {
if !*b.inContinuation {
*b.inContinuation = true
defer func() {
*b.inContinuation = false
r := recover()
if r == nil {
return
}
if buildError, ok := r.(BuildError); ok {
b.err = buildError.Err
} else {
panic(r)
}
}()
}
f(arg)
}
func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) {
// Subsequent writes can be ignored if the builder has encountered an error.
if b.err != nil {
return
}
offset := len(b.result)
b.add(make([]byte, lenLen)...)
if b.inContinuation == nil {
b.inContinuation = new(bool)
}
b.child = &Builder{
result: b.result,
fixedSize: b.fixedSize,
offset: offset,
pendingLenLen: lenLen,
pendingIsASN1: isASN1,
inContinuation: b.inContinuation,
}
b.callContinuation(f, b.child)
b.flushChild()
if b.child != nil {
panic("cryptobyte: internal error")
}
}
func (b *Builder) flushChild() {
if b.child == nil {
return
}
b.child.flushChild()
child := b.child
b.child = nil
if child.err != nil {
b.err = child.err
return
}
length := len(child.result) - child.pendingLenLen - child.offset
if length < 0 {
panic("cryptobyte: internal error") // result unexpectedly shrunk
}
if child.pendingIsASN1 {
// For ASN.1, we reserved a single byte for the length. If that turned out
// to be incorrect, we have to move the contents along in order to make
// space.
if child.pendingLenLen != 1 {
panic("cryptobyte: internal error")
}
var lenLen, lenByte uint8
if int64(length) > 0xfffffffe {
b.err = errors.New("pending ASN.1 child too long")
return
} else if length > 0xffffff {
lenLen = 5
lenByte = 0x80 | 4
} else if length > 0xffff {
lenLen = 4
lenByte = 0x80 | 3
} else if length > 0xff {
lenLen = 3
lenByte = 0x80 | 2
} else if length > 0x7f {
lenLen = 2
lenByte = 0x80 | 1
} else {
lenLen = 1
lenByte = uint8(length)
length = 0
}
// Insert the initial length byte, make space for successive length bytes,
// and adjust the offset.
child.result[child.offset] = lenByte
extraBytes := int(lenLen - 1)
if extraBytes != 0 {
child.add(make([]byte, extraBytes)...)
childStart := child.offset + child.pendingLenLen
copy(child.result[childStart+extraBytes:], child.result[childStart:])
}
child.offset++
child.pendingLenLen = extraBytes
}
l := length
for i := child.pendingLenLen - 1; i >= 0; i-- {
child.result[child.offset+i] = uint8(l)
l >>= 8
}
if l != 0 {
b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen)
return
}
if !b.fixedSize {
b.result = child.result // In case child reallocated result.
}
}
func (b *Builder) add(bytes ...byte) {
if b.err != nil {
return
}
if b.child != nil {
panic("attempted write while child is pending")
}
if len(b.result)+len(bytes) < len(bytes) {
b.err = errors.New("cryptobyte: length overflow")
}
if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) {
b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")
return
}
b.result = append(b.result, bytes...)
}
// A MarshalingValue marshals itself into a Builder.
type MarshalingValue interface {
// Marshal is called by Builder.AddValue. It receives a pointer to a builder
// to marshal itself into. It may return an error that occurred during
// marshaling, such as unset or invalid values.
Marshal(b *Builder) error
}
// AddValue calls Marshal on v, passing a pointer to the builder to append to.
// If Marshal returns an error, it is set on the Builder so that subsequent
// appends don't have an effect.
func (b *Builder) AddValue(v MarshalingValue) {
err := v.Marshal(b)
if err != nil {
b.err = err
}
}
================================================
FILE: cryptobyte/string.go
================================================
// Copyright 2017 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 cryptobyte contains types that help with parsing and constructing
// length-prefixed, binary messages, including ASN.1 DER. (The asn1 subpackage
// contains useful ASN.1 constants.)
//
// The String type is for parsing. It wraps a []byte slice and provides helper
// functions for consuming structures, value by value.
//
// The Builder type is for constructing messages. It providers helper functions
// for appending values and also for appending length-prefixed submessages –
// without having to worry about calculating the length prefix ahead of time.
//
// See the documentation and examples for the Builder and String types to get
// started.
package cryptobyte
// String represents a string of bytes. It provides methods for parsing
// fixed-length and length-prefixed values from it.
type String []byte
// read advances a String by n bytes and returns them. If less than n bytes
// remain, it returns nil.
func (s *String) read(n int) []byte {
if len(*s) < n {
return nil
}
v := (*s)[:n]
*s = (*s)[n:]
return v
}
// Skip advances the String by n byte and reports whether it was successful.
func (s *String) Skip(n int) bool {
return s.read(n) != nil
}
// ReadUint8 decodes an 8-bit value into out and advances over it. It
// returns true on success and false on error.
func (s *String) ReadUint8(out *uint8) bool {
v := s.read(1)
if v == nil {
return false
}
*out = uint8(v[0])
return true
}
// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it.
// It returns true on success and false on error.
func (s *String) ReadUint16(out *uint16) bool {
v := s.read(2)
if v == nil {
return false
}
*out = uint16(v[0])<<8 | uint16(v[1])
return true
}
// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it.
// It returns true on success and false on error.
func (s *String) ReadUint24(out *uint32) bool {
v := s.read(3)
if v == nil {
return false
}
*out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2])
return true
}
// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it.
// It returns true on success and false on error.
func (s *String) ReadUint32(out *uint32) bool {
v := s.read(4)
if v == nil {
return false
}
*out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3])
return true
}
func (s *String) readUnsigned(out *uint32, length int) bool {
v := s.read(length)
if v == nil {
return false
}
var result uint32
for i := 0; i < length; i++ {
result <<= 8
result |= uint32(v[i])
}
*out = result
return true
}
func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool {
lenBytes := s.read(lenLen)
if lenBytes == nil {
return false
}
var length uint32
for _, b := range lenBytes {
length = length << 8
length = length | uint32(b)
}
if int(length) < 0 {
// This currently cannot overflow because we read uint24 at most, but check
// anyway in case that changes in the future.
return false
}
v := s.read(int(length))
if v == nil {
return false
}
*outChild = v
return true
}
// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value
// into out and advances over it. It returns true on success and false on
// error.
func (s *String) ReadUint8LengthPrefixed(out *String) bool {
return s.readLengthPrefixed(1, out)
}
// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit
// length-prefixed value into out and advances over it. It returns true on
// success and false on error.
func (s *String) ReadUint16LengthPrefixed(out *String) bool {
return s.readLengthPrefixed(2, out)
}
// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit
// length-prefixed value into out and advances over it. It returns true on
// success and false on error.
func (s *String) ReadUint24LengthPrefixed(out *String) bool {
return s.readLengthPrefixed(3, out)
}
// ReadBytes reads n bytes into out and advances over them. It returns true on
// success and false and error.
func (s *String) ReadBytes(out *[]byte, n int) bool {
v := s.read(n)
if v == nil {
return false
}
*out = v
return true
}
// CopyBytes copies len(out) bytes into out and advances over them. It returns
// true on success and false on error.
func (s *String) CopyBytes(out []byte) bool {
n := len(out)
v := s.read(n)
if v == nil {
return false
}
return copy(out, v) == n
}
// Empty reports whether the string does not contain any bytes.
func (s String) Empty() bool {
return len(s) == 0
}
================================================
FILE: go.mod
================================================
module github.com/ZZMarquis/gm
go 1.12
================================================
FILE: sm2/cert/gmx509.go
================================================
package cert
import (
"bytes"
"crypto/elliptic"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"errors"
"fmt"
"math/big"
"net"
"net/url"
"strconv"
"strings"
"time"
"unicode/utf8"
"github.com/ZZMarquis/gm/cryptobyte"
cryptobyte_asn1 "github.com/ZZMarquis/gm/cryptobyte/asn1"
"github.com/ZZMarquis/gm/sm2"
)
var (
oidSM2P256V1 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301}
oidSignatureSM3WithSM2 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 501}
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
oidExtensionSubjectKeyId = []int{2, 5, 29, 14}
oidExtensionKeyUsage = []int{2, 5, 29, 15}
oidExtensionExtendedKeyUsage = []int{2, 5, 29, 37}
oidExtensionAuthorityKeyId = []int{2, 5, 29, 35}
oidExtensionBasicConstraints = []int{2, 5, 29, 19}
oidExtensionSubjectAltName = []int{2, 5, 29, 17}
oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
oidExtensionNameConstraints = []int{2, 5, 29, 30}
oidExtensionCRLDistributionPoints = []int{2, 5, 29, 31}
oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1}
oidAuthorityInfoAccessOcsp = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1}
oidAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2}
)
const (
nameTypeEmail = 1
nameTypeDNS = 2
nameTypeURI = 6
nameTypeIP = 7
)
type publicKeyInfo struct {
Raw asn1.RawContent
Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
}
type tbsCertificateRequest struct {
Raw asn1.RawContent
Version int
Subject asn1.RawValue
PublicKey publicKeyInfo
RawAttributes []asn1.RawValue `asn1:"tag:0"`
}
type certificateRequest struct {
Raw asn1.RawContent
TBSCSR tbsCertificateRequest
SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}
func CreateCertificateRequest(template *x509.CertificateRequest, pub *sm2.PublicKey,
pri *sm2.PrivateKey, userId []byte) (csr []byte, err error) {
var publicKeyBytes []byte
var publicKeyAlgorithm pkix.AlgorithmIdentifier
publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub)
if err != nil {
return nil, err
}
var extensions []pkix.Extension
if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) &&
!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs)
if err != nil {
return nil, err
}
extensions = append(extensions, pkix.Extension{
Id: oidExtensionSubjectAltName,
Value: sanBytes,
})
}
extensions = append(extensions, template.ExtraExtensions...)
var attributes []pkix.AttributeTypeAndValueSET
attributes = append(attributes, template.Attributes...)
if len(extensions) > 0 {
// specifiedExtensions contains all the extensions that we
// found specified via template.Attributes.
specifiedExtensions := make(map[string]bool)
for _, atvSet := range template.Attributes {
if !atvSet.Type.Equal(oidExtensionRequest) {
continue
}
for _, atvs := range atvSet.Value {
for _, atv := range atvs {
specifiedExtensions[atv.Type.String()] = true
}
}
}
atvs := make([]pkix.AttributeTypeAndValue, 0, len(extensions))
for _, e := range extensions {
if specifiedExtensions[e.Id.String()] {
// Attributes already contained a value for
// this extension and it takes priority.
continue
}
atvs = append(atvs, pkix.AttributeTypeAndValue{
// There is no place for the critical flag in a CSR.
Type: e.Id,
Value: e.Value,
})
}
// Append the extensions to an existing attribute if possible.
appended := false
for _, atvSet := range attributes {
if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 {
continue
}
atvSet.Value[0] = append(atvSet.Value[0], atvs...)
appended = true
break
}
// Otherwise, add a new attribute for the extensions.
if !appended {
attributes = append(attributes, pkix.AttributeTypeAndValueSET{
Type: oidExtensionRequest,
Value: [][]pkix.AttributeTypeAndValue{
atvs,
},
})
}
}
asn1Subject := template.RawSubject
if len(asn1Subject) == 0 {
asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence())
if err != nil {
return
}
}
rawAttributes, err := newRawAttributes(attributes)
if err != nil {
return
}
tbsCSR := tbsCertificateRequest{
Version: 0, // PKCS #10, RFC 2986
Subject: asn1.RawValue{FullBytes: asn1Subject},
PublicKey: publicKeyInfo{
Algorithm: publicKeyAlgorithm,
PublicKey: asn1.BitString{
Bytes: publicKeyBytes,
BitLength: len(publicKeyBytes) * 8,
},
},
RawAttributes: rawAttributes,
}
tbsCSRContents, err := asn1.Marshal(tbsCSR)
if err != nil {
return
}
tbsCSR.Raw = tbsCSRContents
var signature []byte
signature, err = sm2.Sign(pri, userId, tbsCSRContents)
if err != nil {
return
}
var sigAlgo pkix.AlgorithmIdentifier
sigAlgo.Algorithm = oidSignatureSM3WithSM2
return asn1.Marshal(certificateRequest{
TBSCSR: tbsCSR,
SignatureAlgorithm: sigAlgo,
SignatureValue: asn1.BitString{
Bytes: signature,
BitLength: len(signature) * 8,
},
})
}
// marshalSANs marshals a list of addresses into a the contents of an X.509
// SubjectAlternativeName extension.
func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL) (derBytes []byte, err error) {
var rawValues []asn1.RawValue
for _, name := range dnsNames {
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeDNS, Class: 2, Bytes: []byte(name)})
}
for _, email := range emailAddresses {
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeEmail, Class: 2, Bytes: []byte(email)})
}
for _, rawIP := range ipAddresses {
// If possible, we always want to encode IPv4 addresses in 4 bytes.
ip := rawIP.To4()
if ip == nil {
ip = rawIP
}
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeIP, Class: 2, Bytes: ip})
}
for _, uri := range uris {
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uri.String())})
}
return asn1.Marshal(rawValues)
}
// oidNotInExtensions returns whether an extension with the given oid exists in
// extensions.
func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) bool {
for _, e := range extensions {
if e.Id.Equal(oid) {
return true
}
}
return false
}
func marshalPublicKey(pub *sm2.PublicKey) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) {
publicKeyBytes = pub.GetUnCompressBytes()
publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA
var paramBytes []byte
paramBytes, err = asn1.Marshal(oidSM2P256V1)
publicKeyAlgorithm.Parameters.FullBytes = paramBytes
err = nil
return
}
// newRawAttributes converts AttributeTypeAndValueSETs from a template
// CertificateRequest's Attributes into tbsCertificateRequest RawAttributes.
func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) {
var rawAttributes []asn1.RawValue
b, err := asn1.Marshal(attributes)
if err != nil {
return nil, err
}
rest, err := asn1.Unmarshal(b, &rawAttributes)
if err != nil {
return nil, err
}
if len(rest) != 0 {
return nil, errors.New("x509: failed to unmarshal raw CSR Attributes")
}
return rawAttributes, nil
}
// ParseCertificateRequest parses a single certificate request from the
// given ASN.1 DER data.
func ParseCertificateRequest(asn1Data []byte) (*x509.CertificateRequest, error) {
var csr certificateRequest
rest, err := asn1.Unmarshal(asn1Data, &csr)
if err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, asn1.SyntaxError{Msg: "trailing data"}
}
return parseCertificateRequest(&csr)
}
func parseCertificateRequest(in *certificateRequest) (*x509.CertificateRequest, error) {
out := &x509.CertificateRequest{
Raw: in.Raw,
RawTBSCertificateRequest: in.TBSCSR.Raw,
RawSubjectPublicKeyInfo: in.TBSCSR.PublicKey.Raw,
RawSubject: in.TBSCSR.Subject.FullBytes,
Signature: in.SignatureValue.RightAlign(),
SignatureAlgorithm: 0, //与x509.go里的实现不一样,因为这里都是固定了使用SM3WithSM2
PublicKeyAlgorithm: 0, //与x509.go里的实现不一样,因为这里都是固定了使用EC公钥
Version: in.TBSCSR.Version,
Attributes: parseRawAttributes(in.TBSCSR.RawAttributes),
}
if !oidSignatureSM3WithSM2.Equal(in.SignatureAlgorithm.Algorithm) {
return nil, errors.New("x509: illegal signature algorithm OID")
}
if !oidPublicKeyECDSA.Equal(in.TBSCSR.PublicKey.Algorithm.Algorithm) {
return nil, errors.New("x509: illegal publick key algorithm OID")
}
var err error
out.PublicKey, err = parsePublicKey(&in.TBSCSR.PublicKey)
if err != nil {
return nil, err
}
var subject pkix.RDNSequence
if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 Subject")
}
out.Subject.FillFromRDNSequence(&subject)
if out.Extensions, err = parseCSRExtensions(in.TBSCSR.RawAttributes); err != nil {
return nil, err
}
for _, extension := range out.Extensions {
if extension.Id.Equal(oidExtensionSubjectAltName) {
out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(extension.Value)
if err != nil {
return nil, err
}
}
}
return out, nil
}
func parsePublicKey(keyData *publicKeyInfo) (interface{}, error) {
paramsData := keyData.Algorithm.Parameters.FullBytes
namedCurveOID := new(asn1.ObjectIdentifier)
rest, err := asn1.Unmarshal(paramsData, namedCurveOID)
if err != nil {
return nil, err
}
if len(rest) != 0 {
return nil, errors.New("x509: trailing data after SM2 parameters")
}
if !oidSM2P256V1.Equal(*namedCurveOID) {
return nil, errors.New("x509: CurveOID is not the OID of SM2P256V1")
}
curve := sm2.GetSm2P256V1()
x, y := elliptic.Unmarshal(curve, keyData.PublicKey.RightAlign())
if x == nil || y == nil {
return nil, errors.New("x509: Unmarshal PublicKey failed")
}
pub := &sm2.PublicKey{
Curve: curve,
X: x,
Y: y,
}
return pub, nil
}
// parseRawAttributes Unmarshals RawAttributes intos AttributeTypeAndValueSETs.
func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET {
var attributes []pkix.AttributeTypeAndValueSET
for _, rawAttr := range rawAttributes {
var attr pkix.AttributeTypeAndValueSET
rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr)
// Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET
// (i.e.: challengePassword or unstructuredName).
if err == nil && len(rest) == 0 {
attributes = append(attributes, attr)
}
}
return attributes
}
// parseCSRExtensions parses the attributes from a CSR and extracts any
// requested extensions.
func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) {
// pkcs10Attribute reflects the Attribute structure from section 4.1 of
// https://tools.ietf.org/html/rfc2986.
type pkcs10Attribute struct {
Id asn1.ObjectIdentifier
Values []asn1.RawValue `asn1:"set"`
}
var ret []pkix.Extension
for _, rawAttr := range rawAttributes {
var attr pkcs10Attribute
if rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr); err != nil || len(rest) != 0 || len(attr.Values) == 0 {
// Ignore attributes that don't parse.
continue
}
if !attr.Id.Equal(oidExtensionRequest) {
continue
}
var extensions []pkix.Extension
if _, err := asn1.Unmarshal(attr.Values[0].FullBytes, &extensions); err != nil {
return nil, err
}
ret = append(ret, extensions...)
}
return ret, nil
}
func forEachSAN(extension []byte, callback func(tag int, data []byte) error) error {
// RFC 5280, 4.2.1.6
// SubjectAltName ::= GeneralNames
//
// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
//
// GeneralName ::= CHOICE {
// otherName [0] OtherName,
// rfc822Name [1] IA5String,
// dNSName [2] IA5String,
// x400Address [3] ORAddress,
// directoryName [4] Name,
// ediPartyName [5] EDIPartyName,
// uniformResourceIdentifier [6] IA5String,
// iPAddress [7] OCTET STRING,
// registeredID [8] OBJECT IDENTIFIER }
var seq asn1.RawValue
rest, err := asn1.Unmarshal(extension, &seq)
if err != nil {
return err
} else if len(rest) != 0 {
return errors.New("x509: trailing data after X.509 extension")
}
if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
return asn1.StructuralError{Msg: "bad SAN sequence"}
}
rest = seq.Bytes
for len(rest) > 0 {
var v asn1.RawValue
rest, err = asn1.Unmarshal(rest, &v)
if err != nil {
return err
}
if err := callback(v.Tag, v.Bytes); err != nil {
return err
}
}
return nil
}
// domainToReverseLabels converts a textual domain name like foo.example.com to
// the list of labels in reverse order, e.g. ["com", "example", "foo"].
func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) {
for len(domain) > 0 {
if i := strings.LastIndexByte(domain, '.'); i == -1 {
reverseLabels = append(reverseLabels, domain)
domain = ""
} else {
reverseLabels = append(reverseLabels, domain[i+1:])
domain = domain[:i]
}
}
if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 {
// An empty label at the end indicates an absolute value.
return nil, false
}
for _, label := range reverseLabels {
if len(label) == 0 {
// Empty labels are otherwise invalid.
return nil, false
}
for _, c := range label {
if c < 33 || c > 126 {
// Invalid character.
return nil, false
}
}
}
return reverseLabels, true
}
func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, err error) {
err = forEachSAN(value, func(tag int, data []byte) error {
switch tag {
case nameTypeEmail:
emailAddresses = append(emailAddresses, string(data))
case nameTypeDNS:
dnsNames = append(dnsNames, string(data))
case nameTypeURI:
uri, err := url.Parse(string(data))
if err != nil {
return fmt.Errorf("x509: cannot parse URI %q: %s", string(data), err)
}
if len(uri.Host) > 0 {
if _, ok := domainToReverseLabels(uri.Host); !ok {
return fmt.Errorf("x509: cannot parse URI %q: invalid domain", string(data))
}
}
uris = append(uris, uri)
case nameTypeIP:
switch len(data) {
case net.IPv4len, net.IPv6len:
ipAddresses = append(ipAddresses, data)
default:
return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data)))
}
}
return nil
})
return
}
func VerifyDERCSRSign(asn1Data []byte, userId []byte) (bool, error) {
csr, err := ParseCertificateRequest(asn1Data)
if err != nil {
return false, err
}
return VerifyCSRSign(csr, userId), nil
}
func VerifyCSRSign(csr *x509.CertificateRequest, userId []byte) bool {
pub := csr.PublicKey.(*sm2.PublicKey)
return sm2.Verify(pub, userId, csr.RawTBSCertificateRequest, csr.Signature)
}
func FillCertificateTemplateByCSR(template *x509.Certificate, csr *x509.CertificateRequest) {
template.Subject = csr.Subject
template.PublicKeyAlgorithm = csr.PublicKeyAlgorithm
template.PublicKey = csr.PublicKey
template.Extensions = csr.Extensions
template.ExtraExtensions = csr.ExtraExtensions
template.DNSNames = csr.DNSNames
template.EmailAddresses = csr.EmailAddresses
template.IPAddresses = csr.IPAddresses
template.URIs = csr.URIs
}
func subjectBytes(cert *x509.Certificate) ([]byte, error) {
if len(cert.RawSubject) > 0 {
return cert.RawSubject, nil
}
return asn1.Marshal(cert.Subject.ToRDNSequence())
}
func reverseBitsInAByte(in byte) byte {
b1 := in>>4 | in<<4
b2 := b1>>2&0x33 | b1<<2&0xcc
b3 := b2>>1&0x55 | b2<<1&0xaa
return b3
}
// asn1BitLength returns the bit-length of bitString by considering the
// most-significant bit in a byte to be the "first" bit. This convention
// matches ASN.1, but differs from almost everything else.
func asn1BitLength(bitString []byte) int {
bitLen := len(bitString) * 8
for i := range bitString {
b := bitString[len(bitString)-i-1]
for bit := uint(0); bit < 8; bit++ {
if (b>>bit)&1 == 1 {
return bitLen
}
bitLen--
}
}
return 0
}
// RFC 5280, 4.2.1.12 Extended Key Usage
//
// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }
//
// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
//
// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
// id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 }
// id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
var (
oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22}
oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1}
)
// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID.
var extKeyUsageOIDs = []struct {
extKeyUsage x509.ExtKeyUsage
oid asn1.ObjectIdentifier
}{
{x509.ExtKeyUsageAny, oidExtKeyUsageAny},
{x509.ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth},
{x509.ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth},
{x509.ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning},
{x509.ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection},
{x509.ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem},
{x509.ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel},
{x509.ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser},
{x509.ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping},
{x509.ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning},
{x509.ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
{x509.ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
{x509.ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning},
{x509.ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning},
}
func oidFromExtKeyUsage(eku x509.ExtKeyUsage) (oid asn1.ObjectIdentifier, ok bool) {
for _, pair := range extKeyUsageOIDs {
if eku == pair.extKeyUsage {
return pair.oid, true
}
}
return
}
type basicConstraints struct {
IsCA bool `asn1:"optional"`
MaxPathLen int `asn1:"optional,default:-1"`
}
// RFC 5280, 4.2.1.1
type authKeyId struct {
Id []byte `asn1:"optional,tag:0"`
}
// RFC 5280, 4.2.2.1
type authorityInfoAccess struct {
Method asn1.ObjectIdentifier
Location asn1.RawValue
}
// RFC 5280 4.2.1.4
type policyInformation struct {
Policy asn1.ObjectIdentifier
// policyQualifiers omitted
}
type distributionPointName struct {
FullName []asn1.RawValue `asn1:"optional,tag:0"`
RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
}
// RFC 5280, 4.2.1.14
type distributionPoint struct {
DistributionPoint distributionPointName `asn1:"optional,tag:0"`
Reason asn1.BitString `asn1:"optional,tag:1"`
CRLIssuer asn1.RawValue `asn1:"optional,tag:2"`
}
func isIA5String(s string) error {
for _, r := range s {
if r >= utf8.RuneSelf {
return fmt.Errorf("x509: %q cannot be encoded as an IA5String", s)
}
}
return nil
}
func buildExtensions(template *x509.Certificate, subjectIsEmpty bool, authorityKeyId []byte) (ret []pkix.Extension, err error) {
ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
n := 0
if template.KeyUsage != 0 &&
!oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) {
ret[n].Id = oidExtensionKeyUsage
ret[n].Critical = true
var a [2]byte
a[0] = reverseBitsInAByte(byte(template.KeyUsage))
a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8))
l := 1
if a[1] != 0 {
l = 2
}
bitString := a[:l]
ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
if err != nil {
return
}
n++
}
if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) &&
!oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) {
ret[n].Id = oidExtensionExtendedKeyUsage
var oids []asn1.ObjectIdentifier
for _, u := range template.ExtKeyUsage {
if oid, ok := oidFromExtKeyUsage(u); ok {
oids = append(oids, oid)
} else {
panic("internal error")
}
}
oids = append(oids, template.UnknownExtKeyUsage...)
ret[n].Value, err = asn1.Marshal(oids)
if err != nil {
return
}
n++
}
if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
// Leaving MaxPathLen as zero indicates that no maximum path
// length is desired, unless MaxPathLenZero is set. A value of
// -1 causes encoding/asn1 to omit the value as desired.
maxPathLen := template.MaxPathLen
if maxPathLen == 0 && !template.MaxPathLenZero {
maxPathLen = -1
}
ret[n].Id = oidExtensionBasicConstraints
ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, maxPathLen})
ret[n].Critical = true
if err != nil {
return
}
n++
}
if len(template.SubjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) {
ret[n].Id = oidExtensionSubjectKeyId
ret[n].Value, err = asn1.Marshal(template.SubjectKeyId)
if err != nil {
return
}
n++
}
if len(authorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) {
ret[n].Id = oidExtensionAuthorityKeyId
ret[n].Value, err = asn1.Marshal(authKeyId{authorityKeyId})
if err != nil {
return
}
n++
}
if (len(template.OCSPServer) > 0 || len(template.IssuingCertificateURL) > 0) &&
!oidInExtensions(oidExtensionAuthorityInfoAccess, template.ExtraExtensions) {
ret[n].Id = oidExtensionAuthorityInfoAccess
var aiaValues []authorityInfoAccess
for _, name := range template.OCSPServer {
aiaValues = append(aiaValues, authorityInfoAccess{
Method: oidAuthorityInfoAccessOcsp,
Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)},
})
}
for _, name := range template.IssuingCertificateURL {
aiaValues = append(aiaValues, authorityInfoAccess{
Method: oidAuthorityInfoAccessIssuers,
Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)},
})
}
ret[n].Value, err = asn1.Marshal(aiaValues)
if err != nil {
return
}
n++
}
if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) &&
!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
ret[n].Id = oidExtensionSubjectAltName
// https://tools.ietf.org/html/rfc5280#section-4.2.1.6
// “If the subject field contains an empty sequence ... then
// subjectAltName extension ... is marked as critical”
ret[n].Critical = subjectIsEmpty
ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs)
if err != nil {
return
}
n++
}
if len(template.PolicyIdentifiers) > 0 &&
!oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) {
ret[n].Id = oidExtensionCertificatePolicies
policies := make([]policyInformation, len(template.PolicyIdentifiers))
for i, policy := range template.PolicyIdentifiers {
policies[i].Policy = policy
}
ret[n].Value, err = asn1.Marshal(policies)
if err != nil {
return
}
n++
}
if (len(template.PermittedDNSDomains) > 0 || len(template.ExcludedDNSDomains) > 0 ||
len(template.PermittedIPRanges) > 0 || len(template.ExcludedIPRanges) > 0 ||
len(template.PermittedEmailAddresses) > 0 || len(template.ExcludedEmailAddresses) > 0 ||
len(template.PermittedURIDomains) > 0 || len(template.ExcludedURIDomains) > 0) &&
!oidInExtensions(oidExtensionNameConstraints, template.ExtraExtensions) {
ret[n].Id = oidExtensionNameConstraints
ret[n].Critical = template.PermittedDNSDomainsCritical
ipAndMask := func(ipNet *net.IPNet) []byte {
maskedIP := ipNet.IP.Mask(ipNet.Mask)
ipAndMask := make([]byte, 0, len(maskedIP)+len(ipNet.Mask))
ipAndMask = append(ipAndMask, maskedIP...)
ipAndMask = append(ipAndMask, ipNet.Mask...)
return ipAndMask
}
serialiseConstraints := func(dns []string, ips []*net.IPNet, emails []string, uriDomains []string) (der []byte, err error) {
var b cryptobyte.Builder
for _, name := range dns {
if err = isIA5String(name); err != nil {
return nil, err
}
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1(cryptobyte_asn1.Tag(2).ContextSpecific(), func(b *cryptobyte.Builder) {
b.AddBytes([]byte(name))
})
})
}
for _, ipNet := range ips {
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1(cryptobyte_asn1.Tag(7).ContextSpecific(), func(b *cryptobyte.Builder) {
b.AddBytes(ipAndMask(ipNet))
})
})
}
for _, email := range emails {
if err = isIA5String(email); err != nil {
return nil, err
}
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific(), func(b *cryptobyte.Builder) {
b.AddBytes([]byte(email))
})
})
}
for _, uriDomain := range uriDomains {
if err = isIA5String(uriDomain); err != nil {
return nil, err
}
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1(cryptobyte_asn1.Tag(6).ContextSpecific(), func(b *cryptobyte.Builder) {
b.AddBytes([]byte(uriDomain))
})
})
}
return b.Bytes()
}
permitted, err := serialiseConstraints(template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains)
if err != nil {
return nil, err
}
excluded, err := serialiseConstraints(template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains)
if err != nil {
return nil, err
}
var b cryptobyte.Builder
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
if len(permitted) > 0 {
b.AddASN1(cryptobyte_asn1.Tag(0).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) {
b.AddBytes(permitted)
})
}
if len(excluded) > 0 {
b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) {
b.AddBytes(excluded)
})
}
})
ret[n].Value, err = b.Bytes()
if err != nil {
return nil, err
}
n++
}
if len(template.CRLDistributionPoints) > 0 &&
!oidInExtensions(oidExtensionCRLDistributionPoints, template.ExtraExtensions) {
ret[n].Id = oidExtensionCRLDistributionPoints
var crlDp []distributionPoint
for _, name := range template.CRLDistributionPoints {
dp := distributionPoint{
DistributionPoint: distributionPointName{
FullName: []asn1.RawValue{
{Tag: 6, Class: 2, Bytes: []byte(name)},
},
},
}
crlDp = append(crlDp, dp)
}
ret[n].Value, err = asn1.Marshal(crlDp)
if err != nil {
return
}
n++
}
// Adding another extension here? Remember to update the maximum number
// of elements in the make() at the top of the function.
return append(ret[:n], template.ExtraExtensions...), nil
}
type validity struct {
NotBefore, NotAfter time.Time
}
type certificate struct {
Raw asn1.RawContent
TBSCertificate TBSCertificate
SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}
type tbsCertificate struct {
Raw asn1.RawContent
Version int `asn1:"optional,explicit,default:0,tag:0"`
SerialNumber *big.Int
SignatureAlgorithm pkix.AlgorithmIdentifier
Issuer asn1.RawValue
Validity validity
Subject asn1.RawValue
PublicKey publicKeyInfo
UniqueId asn1.BitString `asn1:"optional,tag:1"`
SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"`
}
type TBSCertificate tbsCertificate
// emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is
// just an empty SEQUENCE.
var emptyASN1Subject = []byte{0x30, 0}
// 为什么要将构建CertificateInfo和签发证书分开呢?
// 是因为实际应用中的CA密钥大多数都是放在加密卡/加密机中的,签名由加密卡/加密机来完成
func CreateCertificateInfo(template, parent *x509.Certificate, csr *x509.CertificateRequest) (*TBSCertificate, error) {
if template.SerialNumber == nil {
return nil, errors.New("x509: no SerialNumber given")
}
asn1Issuer, err := subjectBytes(parent)
if err != nil {
return nil, err
}
asn1Subject, err := subjectBytes(template)
if err != nil {
return nil, err
}
authorityKeyId := template.AuthorityKeyId
if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 {
authorityKeyId = parent.SubjectKeyId
}
extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId)
if err != nil {
return nil, err
}
var sigAlgo pkix.AlgorithmIdentifier
sigAlgo.Algorithm = oidSignatureSM3WithSM2
var subjectPubKeyInfo publicKeyInfo
rest, err := asn1.Unmarshal(csr.RawSubjectPublicKeyInfo, &subjectPubKeyInfo)
if err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, asn1.SyntaxError{Msg: "trailing data"}
}
c := TBSCertificate{
Version: 2,
SerialNumber: template.SerialNumber,
SignatureAlgorithm: sigAlgo,
Issuer: asn1.RawValue{FullBytes: asn1Issuer},
Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
Subject: asn1.RawValue{FullBytes: asn1Subject},
PublicKey: subjectPubKeyInfo,
Extensions: extensions,
}
tbsCertContents, err := asn1.Marshal(c)
if err != nil {
return nil, err
}
c.Raw = tbsCertContents
return &c, nil
}
func IssueCertificateBySoftCAKey(cinfo *TBSCertificate, caPri *sm2.PrivateKey, userId []byte) ([]byte, error) {
signature, err := sm2.Sign(caPri, userId, cinfo.Raw)
if err != nil {
return nil, err
}
return CreateCertificate(cinfo, signature)
}
func CreateCertificate(cinfo *TBSCertificate, signature []byte) ([]byte, error) {
var sigAlgo pkix.AlgorithmIdentifier
sigAlgo.Algorithm = oidSignatureSM3WithSM2
return asn1.Marshal(certificate{
nil,
*cinfo,
sigAlgo,
asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
}
// ParseCertificate parses a single certificate from the given ASN.1 DER data.
func ParseCertificate(asn1Data []byte) (*x509.Certificate, error) {
var cert certificate
rest, err := asn1.Unmarshal(asn1Data, &cert)
if err != nil {
return nil, err
}
if len(rest) > 0 {
return nil, asn1.SyntaxError{Msg: "trailing data"}
}
return parseCertificate(&cert)
}
func parseCertificate(in *certificate) (*x509.Certificate, error) {
out := new(x509.Certificate)
out.Raw = in.Raw
out.RawTBSCertificate = in.TBSCertificate.Raw
out.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Raw
out.RawSubject = in.TBSCertificate.Subject.FullBytes
out.RawIssuer = in.TBSCertificate.Issuer.FullBytes
out.Signature = in.SignatureValue.RightAlign()
out.SignatureAlgorithm = 0
out.PublicKeyAlgorithm = 0
if !oidSignatureSM3WithSM2.Equal(in.SignatureAlgorithm.Algorithm) {
return nil, errors.New("x509: illegal signature algorithm OID")
}
if !oidPublicKeyECDSA.Equal(in.TBSCertificate.PublicKey.Algorithm.Algorithm) {
return nil, errors.New("x509: illegal publick key algorithm OID")
}
var err error
out.PublicKey, err = parsePublicKey(&in.TBSCertificate.PublicKey)
if err != nil {
return nil, err
}
out.Version = in.TBSCertificate.Version + 1
out.SerialNumber = in.TBSCertificate.SerialNumber
var issuer, subject pkix.RDNSequence
if rest, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 subject")
}
if rest, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 subject")
}
out.Issuer.FillFromRDNSequence(&issuer)
out.Subject.FillFromRDNSequence(&subject)
out.NotBefore = in.TBSCertificate.Validity.NotBefore
out.NotAfter = in.TBSCertificate.Validity.NotAfter
for _, e := range in.TBSCertificate.Extensions {
out.Extensions = append(out.Extensions, e)
unhandled := false
if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
switch e.Id[3] {
case 15:
// RFC 5280, 4.2.1.3
var usageBits asn1.BitString
if rest, err := asn1.Unmarshal(e.Value, &usageBits); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 KeyUsage")
}
var usage int
for i := 0; i < 9; i++ {
if usageBits.At(i) != 0 {
usage |= 1 << uint(i)
}
}
out.KeyUsage = x509.KeyUsage(usage)
case 19:
// RFC 5280, 4.2.1.9
var constraints basicConstraints
if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 BasicConstraints")
}
out.BasicConstraintsValid = true
out.IsCA = constraints.IsCA
out.MaxPathLen = constraints.MaxPathLen
out.MaxPathLenZero = out.MaxPathLen == 0
// TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285)
case 17:
out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value)
if err != nil {
return nil, err
}
if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 && len(out.URIs) == 0 {
// If we didn't parse anything then we do the critical check, below.
unhandled = true
}
case 30:
unhandled, err = parseNameConstraintsExtension(out, e)
if err != nil {
return nil, err
}
case 31:
// RFC 5280, 4.2.1.13
// CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
//
// DistributionPoint ::= SEQUENCE {
// distributionPoint [0] DistributionPointName OPTIONAL,
// reasons [1] ReasonFlags OPTIONAL,
// cRLIssuer [2] GeneralNames OPTIONAL }
//
// DistributionPointName ::= CHOICE {
// fullName [0] GeneralNames,
// nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
var cdp []distributionPoint
if rest, err := asn1.Unmarshal(e.Value, &cdp); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 CRL distribution point")
}
for _, dp := range cdp {
// Per RFC 5280, 4.2.1.13, one of distributionPoint or cRLIssuer may be empty.
if len(dp.DistributionPoint.FullName) == 0 {
continue
}
for _, fullName := range dp.DistributionPoint.FullName {
if fullName.Tag == 6 {
out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(fullName.Bytes))
}
}
}
case 35:
// RFC 5280, 4.2.1.1
var a authKeyId
if rest, err := asn1.Unmarshal(e.Value, &a); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 authority key-id")
}
out.AuthorityKeyId = a.Id
case 37:
// RFC 5280, 4.2.1.12. Extended Key Usage
// id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }
//
// ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
//
// KeyPurposeId ::= OBJECT IDENTIFIER
var keyUsage []asn1.ObjectIdentifier
if rest, err := asn1.Unmarshal(e.Value, &keyUsage); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage")
}
for _, u := range keyUsage {
if extKeyUsage, ok := extKeyUsageFromOID(u); ok {
out.ExtKeyUsage = append(out.ExtKeyUsage, extKeyUsage)
} else {
out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u)
}
}
case 14:
// RFC 5280, 4.2.1.2
var keyid []byte
if rest, err := asn1.Unmarshal(e.Value, &keyid); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 key-id")
}
out.SubjectKeyId = keyid
case 32:
// RFC 5280 4.2.1.4: Certificate Policies
var policies []policyInformation
if rest, err := asn1.Unmarshal(e.Value, &policies); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 certificate policies")
}
out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies))
for i, policy := range policies {
out.PolicyIdentifiers[i] = policy.Policy
}
default:
// Unknown extensions are recorded if critical.
unhandled = true
}
} else if e.Id.Equal(oidExtensionAuthorityInfoAccess) {
// RFC 5280 4.2.2.1: Authority Information Access
var aia []authorityInfoAccess
if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 authority information")
}
for _, v := range aia {
// GeneralName: uniformResourceIdentifier [6] IA5String
if v.Location.Tag != 6 {
continue
}
if v.Method.Equal(oidAuthorityInfoAccessOcsp) {
out.OCSPServer = append(out.OCSPServer, string(v.Location.Bytes))
} else if v.Method.Equal(oidAuthorityInfoAccessIssuers) {
out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes))
}
}
} else {
// Unknown extensions are recorded if critical.
unhandled = true
}
if e.Critical && unhandled {
out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id)
}
}
return out, nil
}
func parseNameConstraintsExtension(out *x509.Certificate, e pkix.Extension) (unhandled bool, err error) {
// RFC 5280, 4.2.1.10
// NameConstraints ::= SEQUENCE {
// permittedSubtrees [0] GeneralSubtrees OPTIONAL,
// excludedSubtrees [1] GeneralSubtrees OPTIONAL }
//
// GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
//
// GeneralSubtree ::= SEQUENCE {
// base GeneralName,
// minimum [0] BaseDistance DEFAULT 0,
// maximum [1] BaseDistance OPTIONAL }
//
// BaseDistance ::= INTEGER (0..MAX)
outer := cryptobyte.String(e.Value)
var toplevel, permitted, excluded cryptobyte.String
var havePermitted, haveExcluded bool
if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) ||
!outer.Empty() ||
!toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) ||
!toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) ||
!toplevel.Empty() {
return false, errors.New("x509: invalid NameConstraints extension")
}
if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 {
// https://tools.ietf.org/html/rfc5280#section-4.2.1.10:
// “either the permittedSubtrees field
// or the excludedSubtrees MUST be
// present”
return false, errors.New("x509: empty name constraints extension")
}
getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) {
for !subtrees.Empty() {
var seq, value cryptobyte.String
var tag cryptobyte_asn1.Tag
if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) ||
!seq.ReadAnyASN1(&value, &tag) {
return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension")
}
var (
dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific()
emailTag = cryptobyte_asn1.Tag(1).ContextSpecific()
ipTag = cryptobyte_asn1.Tag(7).ContextSpecific()
uriTag = cryptobyte_asn1.Tag(6).ContextSpecific()
)
switch tag {
case dnsTag:
domain := string(value)
if err := isIA5String(domain); err != nil {
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
}
trimmedDomain := domain
if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' {
// constraints can have a leading
// period to exclude the domain
// itself, but that's not valid in a
// normal domain name.
trimmedDomain = trimmedDomain[1:]
}
if _, ok := domainToReverseLabels(trimmedDomain); !ok {
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
}
dnsNames = append(dnsNames, domain)
case ipTag:
l := len(value)
var ip, mask []byte
switch l {
case 8:
ip = value[:4]
mask = value[4:]
case 32:
ip = value[:16]
mask = value[16:]
default:
return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l)
}
if !isValidIPMask(mask) {
return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask)
}
ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)})
case emailTag:
constraint := string(value)
if err := isIA5String(constraint); err != nil {
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
}
// If the constraint contains an @ then
// it specifies an exact mailbox name.
if strings.Contains(constraint, "@") {
if _, ok := parseRFC2821Mailbox(constraint); !ok {
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
}
} else {
// Otherwise it's a domain name.
domain := constraint
if len(domain) > 0 && domain[0] == '.' {
domain = domain[1:]
}
if _, ok := domainToReverseLabels(domain); !ok {
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
}
}
emails = append(emails, constraint)
case uriTag:
domain := string(value)
if err := isIA5String(domain); err != nil {
return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
}
if net.ParseIP(domain) != nil {
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
}
trimmedDomain := domain
if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' {
// constraints can have a leading
// period to exclude the domain itself,
// but that's not valid in a normal
// domain name.
trimmedDomain = trimmedDomain[1:]
}
if _, ok := domainToReverseLabels(trimmedDomain); !ok {
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
}
uriDomains = append(uriDomains, domain)
default:
unhandled = true
}
}
return dnsNames, ips, emails, uriDomains, nil
}
if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil {
return false, err
}
if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil {
return false, err
}
out.PermittedDNSDomainsCritical = e.Critical
return unhandled, nil
}
// isValidIPMask returns true iff mask consists of zero or more 1 bits, followed by zero bits.
func isValidIPMask(mask []byte) bool {
seenZero := false
for _, b := range mask {
if seenZero {
if b != 0 {
return false
}
continue
}
switch b {
case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe:
seenZero = true
case 0xff:
default:
return false
}
}
return true
}
// rfc2821Mailbox represents a “mailbox” (which is an email address to most
// people) by breaking it into the “local” (i.e. before the '@') and “domain”
// parts.
type rfc2821Mailbox struct {
local, domain string
}
// parseRFC2821Mailbox parses an email address into local and domain parts,
// based on the ABNF for a “Mailbox” from RFC 2821. According to
// https://tools.ietf.org/html/rfc5280#section-4.2.1.6 that's correct for an
// rfc822Name from a certificate: “The format of an rfc822Name is a "Mailbox"
// as defined in https://tools.ietf.org/html/rfc2821#section-4.1.2”.
func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
if len(in) == 0 {
return mailbox, false
}
localPartBytes := make([]byte, 0, len(in)/2)
if in[0] == '"' {
// Quoted-string = DQUOTE *qcontent DQUOTE
// non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127
// qcontent = qtext / quoted-pair
// qtext = non-whitespace-control /
// %d33 / %d35-91 / %d93-126
// quoted-pair = ("\" text) / obs-qp
// text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text
//
// (Names beginning with “obs-” are the obsolete syntax from
// https://tools.ietf.org/html/rfc2822#section-4. Since it has
// been 16 years, we no longer accept that.)
in = in[1:]
QuotedString:
for {
if len(in) == 0 {
return mailbox, false
}
c := in[0]
in = in[1:]
switch {
case c == '"':
break QuotedString
case c == '\\':
// quoted-pair
if len(in) == 0 {
return mailbox, false
}
if in[0] == 11 ||
in[0] == 12 ||
(1 <= in[0] && in[0] <= 9) ||
(14 <= in[0] && in[0] <= 127) {
localPartBytes = append(localPartBytes, in[0])
in = in[1:]
} else {
return mailbox, false
}
case c == 11 ||
c == 12 ||
// Space (char 32) is not allowed based on the
// BNF, but RFC 3696 gives an example that
// assumes that it is. Several “verified”
// errata continue to argue about this point.
// We choose to accept it.
c == 32 ||
c == 33 ||
c == 127 ||
(1 <= c && c <= 8) ||
(14 <= c && c <= 31) ||
(35 <= c && c <= 91) ||
(93 <= c && c <= 126):
// qtext
localPartBytes = append(localPartBytes, c)
default:
return mailbox, false
}
}
} else {
// Atom ("." Atom)*
NextChar:
for len(in) > 0 {
// atext from https://tools.ietf.org/html/rfc2822#section-3.2.4
c := in[0]
switch {
case c == '\\':
// Examples given in RFC 3696 suggest that
// escaped characters can appear outside of a
// quoted string. Several “verified” errata
// continue to argue the point. We choose to
// accept it.
in = in[1:]
if len(in) == 0 {
return mailbox, false
}
fallthrough
case ('0' <= c && c <= '9') ||
('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') ||
c == '!' || c == '#' || c == '$' || c == '%' ||
c == '&' || c == '\'' || c == '*' || c == '+' ||
c == '-' || c == '/' || c == '=' || c == '?' ||
c == '^' || c == '_' || c == '`' || c == '{' ||
c == '|' || c == '}' || c == '~' || c == '.':
localPartBytes = append(localPartBytes, in[0])
in = in[1:]
default:
break NextChar
}
}
if len(localPartBytes) == 0 {
return mailbox, false
}
// https://tools.ietf.org/html/rfc3696#section-3
// “period (".") may also appear, but may not be used to start
// or end the local part, nor may two or more consecutive
// periods appear.”
twoDots := []byte{'.', '.'}
if localPartBytes[0] == '.' ||
localPartBytes[len(localPartBytes)-1] == '.' ||
bytes.Contains(localPartBytes, twoDots) {
return mailbox, false
}
}
if len(in) == 0 || in[0] != '@' {
return mailbox, false
}
in = in[1:]
// The RFC species a format for domains, but that's known to be
// violated in practice so we accept that anything after an '@' is the
// domain part.
if _, ok := domainToReverseLabels(in); !ok {
return mailbox, false
}
mailbox.local = string(localPartBytes)
mailbox.domain = in
return mailbox, true
}
func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku x509.ExtKeyUsage, ok bool) {
for _, pair := range extKeyUsageOIDs {
if oid.Equal(pair.oid) {
return pair.extKeyUsage, true
}
}
return
}
================================================
FILE: sm2/cert/gmx509_test.go
================================================
package cert
import (
"bytes"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"fmt"
"io/ioutil"
"math/big"
"testing"
"time"
"github.com/ZZMarquis/gm/sm2"
)
func TestX500Name(t *testing.T) {
name := new(pkix.Name)
name.CommonName = "ID=Mock Root CA"
name.Country = []string{"CN"}
name.Province = []string{"Beijing"}
name.Locality = []string{"Beijing"}
name.Organization = []string{"org.zz"}
name.OrganizationalUnit = []string{"org.zz"}
fmt.Println(name.String())
}
func TestCreateCertificateRequest(t *testing.T) {
pri, pub, err := sm2.GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
sanContents, err := marshalSANs([]string{"foo.example.com"}, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
template := x509.CertificateRequest{
Subject: pkix.Name{
CommonName: "test.example.com",
Organization: []string{"Σ Acme Co"},
},
DNSNames: []string{"test.example.com"},
// An explicit extension should override the DNSNames from the
// template.
ExtraExtensions: []pkix.Extension{
{
Id: oidExtensionSubjectAltName,
Value: sanContents,
},
},
}
derBytes, err := CreateCertificateRequest(&template, pub, pri, nil)
if err != nil {
t.Fatal(err)
}
ioutil.WriteFile("sample.csr", derBytes, 0644)
csr, err := ParseCertificateRequest(derBytes)
if err != nil {
t.Fatal(err)
}
csrPub := csr.PublicKey.(*sm2.PublicKey)
if !bytes.Equal(pub.GetUnCompressBytes(), csrPub.GetUnCompressBytes()) {
t.Fatal("public key not equals")
}
b, err := VerifyDERCSRSign(derBytes, nil)
if err != nil {
t.Fatal(err)
}
if !b {
t.Fatal("Verify CSR sign not pass")
}
}
func TestCreateCertificate(t *testing.T) {
pri, pub, err := sm2.GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
sanContents, err := marshalSANs([]string{"foo.example.com"}, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
template := x509.CertificateRequest{
Subject: pkix.Name{
CommonName: "test.example.com",
Organization: []string{"Σ Acme Co"},
},
DNSNames: []string{"test.example.com"},
// An explicit extension should override the DNSNames from the
// template.
ExtraExtensions: []pkix.Extension{
{
Id: oidExtensionSubjectAltName,
Value: sanContents,
},
},
}
derBytes, err := CreateCertificateRequest(&template, pub, pri, nil)
if err != nil {
t.Fatal(err)
}
csr, err := ParseCertificateRequest(derBytes)
if err != nil {
t.Fatal(err)
}
testExtKeyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
testUnknownExtKeyUsage := []asn1.ObjectIdentifier{[]int{1, 2, 3}, []int{2, 59, 1}}
cerTemplate := x509.Certificate{
// SerialNumber is negative to ensure that negative
// values are parsed. This is due to the prevalence of
// buggy code that produces certificates with negative
// serial numbers.
SerialNumber: big.NewInt(-1),
NotBefore: time.Now(),
NotAfter: time.Unix(time.Now().Unix()+100000000, 0),
SubjectKeyId: []byte{1, 2, 3, 4},
KeyUsage: x509.KeyUsageCertSign,
ExtKeyUsage: testExtKeyUsage,
UnknownExtKeyUsage: testUnknownExtKeyUsage,
BasicConstraintsValid: true,
IsCA: true,
OCSPServer: []string{"http://ocsp.example.com"},
IssuingCertificateURL: []string{"http://crt.example.com/ca1.crt"},
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"},
}
FillCertificateTemplateByCSR(&cerTemplate, csr)
cinfo, err := CreateCertificateInfo(&cerTemplate, &cerTemplate, csr)
if err != nil {
t.Fatal(err)
}
sign, err := sm2.Sign(pri, nil, cinfo.Raw)
if err != nil {
t.Fatal(err)
}
cer, err := CreateCertificate(cinfo, sign)
if err != nil {
t.Fatal(err)
}
ioutil.WriteFile("sample.cer", cer, 0644)
certificate, err := ParseCertificate(cer)
if err != nil {
t.Fatal(err)
}
fmt.Println(certificate.DNSNames)
}
================================================
FILE: sm2/keyexchange.go
================================================
package sm2
import (
"bytes"
"encoding/binary"
"errors"
"github.com/ZZMarquis/gm/sm3"
"github.com/ZZMarquis/gm/util"
"hash"
"math/big"
)
type ExchangeResult struct {
Key []byte
S1 []byte
S2 []byte
}
func reduce(x *big.Int, w int) *big.Int {
intOne := new(big.Int).SetInt64(1)
result := util.Lsh(intOne, uint(w))
result = util.Sub(result, intOne)
result = util.And(x, result)
result = util.SetBit(result, w, 1)
return result
}
func calculateU(w int, selfStaticPriv *PrivateKey, selfEphemeralPriv *PrivateKey, selfEphemeralPub *PublicKey,
otherStaticPub *PublicKey, otherEphemeralPub *PublicKey) (x *big.Int, y *big.Int) {
x1 := reduce(selfEphemeralPub.X, w)
x2 := reduce(otherEphemeralPub.X, w)
tA := util.Mul(x1, selfEphemeralPriv.D)
tA = util.Add(selfStaticPriv.D, tA)
k1 := util.Mul(sm2H, tA)
k1 = util.Mod(k1, selfStaticPriv.Curve.N)
k2 := util.Mul(k1, x2)
k2 = util.Mod(k2, selfStaticPriv.Curve.N)
p1x, p1y := selfStaticPriv.Curve.ScalarMult(otherStaticPub.X, otherStaticPub.Y, k1.Bytes())
p2x, p2y := selfStaticPriv.Curve.ScalarMult(otherEphemeralPub.X, otherEphemeralPub.Y, k2.Bytes())
x, y = selfStaticPriv.Curve.Add(p1x, p1y, p2x, p2y)
return
}
func kdfForExch(digest hash.Hash, ux, uy *big.Int, za, zb []byte, keyBits int) []byte {
bufSize := 4
if bufSize < digest.BlockSize() {
bufSize = digest.BlockSize()
}
buf := make([]byte, bufSize)
rv := make([]byte, (keyBits+7)/8)
rvLen := len(rv)
uxBytes := ux.Bytes()
uyBytes := uy.Bytes()
off := 0
ct := uint32(0)
for off < rvLen {
digest.Reset()
digest.Write(uxBytes)
digest.Write(uyBytes)
digest.Write(za)
digest.Write(zb)
ct++
binary.BigEndian.PutUint32(buf, ct)
digest.Write(buf[:4])
tmp := digest.Sum(nil)
copy(buf[:bufSize], tmp[:bufSize])
copyLen := rvLen - off
copy(rv[off:off+copyLen], buf[:copyLen])
off += copyLen
}
return rv
}
func calculateInnerHash(digest hash.Hash, ux *big.Int, za, zb []byte, p1x, p1y *big.Int, p2x, p2y *big.Int) []byte {
digest.Reset()
digest.Write(ux.Bytes())
digest.Write(za)
digest.Write(zb)
digest.Write(p1x.Bytes())
digest.Write(p1y.Bytes())
digest.Write(p2x.Bytes())
digest.Write(p2y.Bytes())
return digest.Sum(nil)
}
func s1(digest hash.Hash, uy *big.Int, innerHash []byte) []byte {
digest.Reset()
digest.Write([]byte{0x02})
digest.Write(uy.Bytes())
digest.Write(innerHash)
return digest.Sum(nil)
}
func s2(digest hash.Hash, uy *big.Int, innerHash []byte) []byte {
digest.Reset()
digest.Write([]byte{0x03})
digest.Write(uy.Bytes())
digest.Write(innerHash)
return digest.Sum(nil)
}
func CalculateKeyWithConfirmation(initiator bool, keyBits int, confirmationTag []byte,
selfStaticPriv *PrivateKey, selfEphemeralPriv *PrivateKey, selfId []byte,
otherStaticPub *PublicKey, otherEphemeralPub *PublicKey, otherId []byte) (*ExchangeResult, error) {
if selfId == nil {
selfId = make([]byte, 0)
}
if otherId == nil {
otherId = make([]byte, 0)
}
if initiator && confirmationTag == nil {
return nil, errors.New("if initiating, confirmationTag must be set")
}
selfStaticPub := CalculatePubKey(selfStaticPriv)
digest := sm3.New()
za := getZ(digest, &selfStaticPriv.Curve, selfStaticPub.X, selfStaticPub.Y, selfId)
zb := getZ(digest, &selfStaticPriv.Curve, otherStaticPub.X, otherStaticPub.Y, otherId)
w := selfStaticPriv.Curve.BitSize/2 - 1
selfEphemeralPub := CalculatePubKey(selfEphemeralPriv)
ux, uy := calculateU(w, selfStaticPriv, selfEphemeralPriv, selfEphemeralPub, otherStaticPub, otherEphemeralPub)
if initiator {
rv := kdfForExch(digest, ux, uy, za, zb, keyBits)
innerHash := calculateInnerHash(digest, ux, za, zb, selfEphemeralPub.X, selfEphemeralPub.Y,
otherEphemeralPub.X, otherEphemeralPub.Y)
s1 := s1(digest, uy, innerHash)
if !bytes.Equal(s1, confirmationTag) {
return nil, errors.New("confirmation tag mismatch")
}
s2 := s2(digest, uy, innerHash)
return &ExchangeResult{Key: rv, S2: s2}, nil
} else {
rv := kdfForExch(digest, ux, uy, zb, za, keyBits)
innerHash := calculateInnerHash(digest, ux, zb, za, otherEphemeralPub.X, otherEphemeralPub.Y,
selfEphemeralPub.X, selfEphemeralPub.Y)
s1 := s1(digest, uy, innerHash)
s2 := s2(digest, uy, innerHash)
return &ExchangeResult{Key: rv, S1: s1, S2: s2}, nil
}
}
func ResponderConfirm(responderS2 []byte, initiatorS2 []byte) bool {
return bytes.Equal(responderS2, initiatorS2)
}
================================================
FILE: sm2/keyexchange_test.go
================================================
package sm2
import (
"crypto/rand"
"testing"
)
const (
KeyBits = 128
)
var (
initiatorId = []byte("ABCDEFG1234")
responderId = []byte("1234567ABCD")
)
func TestSM2KeyExchange(t *testing.T) {
initiatorStaticPriv, initiatorStaticPub, _ := GenerateKey(rand.Reader)
initiatorEphemeralPriv, initiatorEphemeralPub, _ := GenerateKey(rand.Reader)
responderStaticPriv, responderStaticPub, _ := GenerateKey(rand.Reader)
responderEphemeralPriv, responderEphemeralPub, _ := GenerateKey(rand.Reader)
responderResult, err := CalculateKeyWithConfirmation(false, KeyBits, nil,
responderStaticPriv, responderEphemeralPriv, responderId,
initiatorStaticPub, initiatorEphemeralPub, initiatorId)
if err != nil {
t.Error(err.Error())
return
}
initiatorResult, err := CalculateKeyWithConfirmation(true, KeyBits, responderResult.S1,
initiatorStaticPriv, initiatorEphemeralPriv, initiatorId,
responderStaticPub, responderEphemeralPub, responderId)
if err != nil {
t.Error(err.Error())
return
}
if !ResponderConfirm(responderResult.S2, initiatorResult.S2) {
t.Error("responder confirm s2 failed")
return
}
}
================================================
FILE: sm2/sm2.go
================================================
package sm2
import (
"bytes"
"crypto/elliptic"
"crypto/rand"
"encoding/asn1"
"encoding/binary"
"errors"
"fmt"
"hash"
"io"
"math/big"
"github.com/ZZMarquis/gm/sm3"
"github.com/ZZMarquis/gm/util"
)
const (
BitSize = 256
KeyBytes = (BitSize + 7) / 8
UnCompress = 0x04
)
type Sm2CipherTextType int32
const (
// 旧标准的密文顺序
C1C2C3 Sm2CipherTextType = 1
// [GM/T 0009-2012]标准规定的顺序
C1C3C2 Sm2CipherTextType = 2
)
var (
sm2H = new(big.Int).SetInt64(1)
sm2SignDefaultUserId = []byte{
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}
)
var sm2P256V1 P256V1Curve
type P256V1Curve struct {
*elliptic.CurveParams
A *big.Int
}
type PublicKey struct {
X, Y *big.Int
Curve P256V1Curve
}
type PrivateKey struct {
D *big.Int
Curve P256V1Curve
}
type sm2Signature struct {
R, S *big.Int
}
type sm2CipherC1C3C2 struct {
X, Y *big.Int
C3 []byte
C2 []byte
}
type sm2CipherC1C2C3 struct {
X, Y *big.Int
C2 []byte
C3 []byte
}
func init() {
initSm2P256V1()
}
func initSm2P256V1() {
sm2P, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16)
sm2A, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16)
sm2B, _ := new(big.Int).SetString("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16)
sm2N, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
sm2Gx, _ := new(big.Int).SetString("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16)
sm2Gy, _ := new(big.Int).SetString("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16)
sm2P256V1.CurveParams = &elliptic.CurveParams{Name: "SM2-P-256-V1"}
sm2P256V1.P = sm2P
sm2P256V1.A = sm2A
sm2P256V1.B = sm2B
sm2P256V1.N = sm2N
sm2P256V1.Gx = sm2Gx
sm2P256V1.Gy = sm2Gy
sm2P256V1.BitSize = BitSize
}
func GetSm2P256V1() P256V1Curve {
return sm2P256V1
}
func GenerateKey(rand io.Reader) (*PrivateKey, *PublicKey, error) {
priv, x, y, err := elliptic.GenerateKey(sm2P256V1, rand)
if err != nil {
return nil, nil, err
}
privateKey := new(PrivateKey)
privateKey.Curve = sm2P256V1
privateKey.D = new(big.Int).SetBytes(priv)
publicKey := new(PublicKey)
publicKey.Curve = sm2P256V1
publicKey.X = x
publicKey.Y = y
return privateKey, publicKey, nil
}
func RawBytesToPublicKey(bytes []byte) (*PublicKey, error) {
if len(bytes) != KeyBytes*2 {
return nil, errors.New(fmt.Sprintf("Public key raw bytes length must be %d", KeyBytes*2))
}
publicKey := new(PublicKey)
publicKey.Curve = sm2P256V1
publicKey.X = new(big.Int).SetBytes(bytes[:KeyBytes])
publicKey.Y = new(big.Int).SetBytes(bytes[KeyBytes:])
return publicKey, nil
}
func RawBytesToPrivateKey(bytes []byte) (*PrivateKey, error) {
if len(bytes) != KeyBytes {
return nil, errors.New(fmt.Sprintf("Private key raw bytes length must be %d", KeyBytes))
}
privateKey := new(PrivateKey)
privateKey.Curve = sm2P256V1
privateKey.D = new(big.Int).SetBytes(bytes)
return privateKey, nil
}
func (pub *PublicKey) GetUnCompressBytes() []byte {
xBytes := bigIntTo32Bytes(pub.X)
yBytes := bigIntTo32Bytes(pub.Y)
xl := len(xBytes)
yl := len(yBytes)
raw := make([]byte, 1+KeyBytes*2)
raw[0] = UnCompress
if xl > KeyBytes {
copy(raw[1:1+KeyBytes], xBytes[xl-KeyBytes:])
} else if xl < KeyBytes {
copy(raw[1+(KeyBytes-xl):1+KeyBytes], xBytes)
} else {
copy(raw[1:1+KeyBytes], xBytes)
}
if yl > KeyBytes {
copy(raw[1+KeyBytes:], yBytes[yl-KeyBytes:])
} else if yl < KeyBytes {
copy(raw[1+KeyBytes+(KeyBytes-yl):], yBytes)
} else {
copy(raw[1+KeyBytes:], yBytes)
}
return raw
}
func (pub *PublicKey) GetRawBytes() []byte {
raw := pub.GetUnCompressBytes()
return raw[1:]
}
func (pri *PrivateKey) GetRawBytes() []byte {
dBytes := bigIntTo32Bytes(pri.D)
dl := len(dBytes)
if dl > KeyBytes {
raw := make([]byte, KeyBytes)
copy(raw, dBytes[dl-KeyBytes:])
return raw
} else if dl < KeyBytes {
raw := make([]byte, KeyBytes)
copy(raw[KeyBytes-dl:], dBytes)
return raw
} else {
return dBytes
}
}
func CalculatePubKey(priv *PrivateKey) *PublicKey {
pub := new(PublicKey)
pub.Curve = priv.Curve
pub.X, pub.Y = priv.Curve.ScalarBaseMult(priv.D.Bytes())
return pub
}
func nextK(rnd io.Reader, max *big.Int) (*big.Int, error) {
intOne := new(big.Int).SetInt64(1)
var k *big.Int
var err error
for {
k, err = rand.Int(rnd, max)
if err != nil {
return nil, err
}
if k.Cmp(intOne) >= 0 {
return k, err
}
}
}
func xor(data []byte, kdfOut []byte, dRemaining int) {
for i := 0; i != dRemaining; i++ {
data[i] ^= kdfOut[i]
}
}
// 表示SM2 Key的大数比较小时,直接通过Bytes()函数得到的字节数组可能不够32字节,这个时候要补齐成32字节
func bigIntTo32Bytes(bn *big.Int) []byte {
byteArr := bn.Bytes()
byteArrLen := len(byteArr)
if byteArrLen == KeyBytes {
return byteArr
}
byteArr = append(make([]byte, KeyBytes-byteArrLen), byteArr...)
return byteArr
}
func kdf(digest hash.Hash, c1x *big.Int, c1y *big.Int, encData []byte) {
bufSize := 4
if bufSize < digest.Size() {
bufSize = digest.Size()
}
buf := make([]byte, bufSize)
encDataLen := len(encData)
c1xBytes := bigIntTo32Bytes(c1x)
c1yBytes := bigIntTo32Bytes(c1y)
off := 0
ct := uint32(0)
for off < encDataLen {
digest.Reset()
digest.Write(c1xBytes)
digest.Write(c1yBytes)
ct++
binary.BigEndian.PutUint32(buf, ct)
digest.Write(buf[:4])
tmp := digest.Sum(nil)
copy(buf[:bufSize], tmp[:bufSize])
xorLen := encDataLen - off
if xorLen > digest.Size() {
xorLen = digest.Size()
}
xor(encData[off:], buf, xorLen)
off += xorLen
}
}
func notEncrypted(encData []byte, in []byte) bool {
encDataLen := len(encData)
for i := 0; i != encDataLen; i++ {
if encData[i] != in[i] {
return false
}
}
return true
}
func Encrypt(pub *PublicKey, in []byte, cipherTextType Sm2CipherTextType) ([]byte, error) {
c2 := make([]byte, len(in))
copy(c2, in)
var c1 []byte
digest := sm3.New()
var kPBx, kPBy *big.Int
for {
k, err := nextK(rand.Reader, pub.Curve.N)
if err != nil {
return nil, err
}
kBytes := k.Bytes()
c1x, c1y := pub.Curve.ScalarBaseMult(kBytes)
c1 = elliptic.Marshal(pub.Curve, c1x, c1y)
kPBx, kPBy = pub.Curve.ScalarMult(pub.X, pub.Y, kBytes)
kdf(digest, kPBx, kPBy, c2)
if !notEncrypted(c2, in) {
break
}
}
digest.Reset()
digest.Write(bigIntTo32Bytes(kPBx))
digest.Write(in)
digest.Write(bigIntTo32Bytes(kPBy))
c3 := digest.Sum(nil)
c1Len := len(c1)
c2Len := len(c2)
c3Len := len(c3)
result := make([]byte, c1Len+c2Len+c3Len)
if cipherTextType == C1C2C3 {
copy(result[:c1Len], c1)
copy(result[c1Len:c1Len+c2Len], c2)
copy(result[c1Len+c2Len:], c3)
} else if cipherTextType == C1C3C2 {
copy(result[:c1Len], c1)
copy(result[c1Len:c1Len+c3Len], c3)
copy(result[c1Len+c3Len:], c2)
} else {
return nil, errors.New("unknown cipherTextType:" + string(cipherTextType))
}
return result, nil
}
func Decrypt(priv *PrivateKey, in []byte, cipherTextType Sm2CipherTextType) ([]byte, error) {
c1Len := ((priv.Curve.BitSize+7)>>3)*2 + 1
c1 := make([]byte, c1Len)
copy(c1, in[:c1Len])
c1x, c1y := elliptic.Unmarshal(priv.Curve, c1)
sx, sy := priv.Curve.ScalarMult(c1x, c1y, sm2H.Bytes())
if util.IsEcPointInfinity(sx, sy) {
return nil, errors.New("[h]C1 at infinity")
}
c1x, c1y = priv.Curve.ScalarMult(c1x, c1y, priv.D.Bytes())
digest := sm3.New()
c3Len := digest.Size()
c2Len := len(in) - c1Len - c3Len
c2 := make([]byte, c2Len)
c3 := make([]byte, c3Len)
if cipherTextType == C1C2C3 {
copy(c2, in[c1Len:c1Len+c2Len])
copy(c3, in[c1Len+c2Len:])
} else if cipherTextType == C1C3C2 {
copy(c3, in[c1Len:c1Len+c3Len])
copy(c2, in[c1Len+c3Len:])
} else {
return nil, errors.New("unknown cipherTextType:" + string(cipherTextType))
}
kdf(digest, c1x, c1y, c2)
digest.Reset()
digest.Write(bigIntTo32Bytes(c1x))
digest.Write(c2)
digest.Write(bigIntTo32Bytes(c1y))
newC3 := digest.Sum(nil)
if !bytes.Equal(newC3, c3) {
return nil, errors.New("invalid cipher text")
}
return c2, nil
}
func MarshalCipher(in []byte, cipherTextType Sm2CipherTextType) ([]byte, error) {
byteLen := (sm2P256V1.Params().BitSize + 7) >> 3
c1x := make([]byte, byteLen)
c1y := make([]byte, byteLen)
c2Len := len(in) - (1 + byteLen*2) - sm3.DigestLength
c2 := make([]byte, c2Len)
c3 := make([]byte, sm3.DigestLength)
pos := 1
copy(c1x, in[pos:pos+byteLen])
pos += byteLen
copy(c1y, in[pos:pos+byteLen])
pos += byteLen
nc1x := new(big.Int).SetBytes(c1x)
nc1y := new(big.Int).SetBytes(c1y)
if cipherTextType == C1C2C3 {
copy(c2, in[pos:pos+c2Len])
pos += c2Len
copy(c3, in[pos:pos+sm3.DigestLength])
result, err := asn1.Marshal(sm2CipherC1C2C3{nc1x, nc1y, c2, c3})
if err != nil {
return nil, err
}
return result, nil
} else if cipherTextType == C1C3C2 {
copy(c3, in[pos:pos+sm3.DigestLength])
pos += sm3.DigestLength
copy(c2, in[pos:pos+c2Len])
result, err := asn1.Marshal(sm2CipherC1C3C2{nc1x, nc1y, c3, c2})
if err != nil {
return nil, err
}
return result, nil
} else {
return nil, errors.New("unknown cipherTextType:" + string(cipherTextType))
}
}
func UnmarshalCipher(in []byte, cipherTextType Sm2CipherTextType) (out []byte, err error) {
if cipherTextType == C1C2C3 {
cipher := new(sm2CipherC1C2C3)
_, err = asn1.Unmarshal(in, cipher)
if err != nil {
return nil, err
}
c1xBytes := bigIntTo32Bytes(cipher.X)
c1yBytes := bigIntTo32Bytes(cipher.Y)
c1xLen := len(c1xBytes)
c1yLen := len(c1yBytes)
c2Len := len(cipher.C2)
c3Len := len(cipher.C3)
result := make([]byte, 1+c1xLen+c1yLen+c2Len+c3Len)
pos := 0
result[pos] = UnCompress
pos += 1
copy(result[pos:pos+c1xLen], c1xBytes)
pos += c1xLen
copy(result[pos:pos+c1yLen], c1yBytes)
pos += c1yLen
copy(result[pos:pos+c2Len], cipher.C2)
pos += c2Len
copy(result[pos:pos+c3Len], cipher.C3)
return result, nil
} else if cipherTextType == C1C3C2 {
cipher := new(sm2CipherC1C3C2)
_, err = asn1.Unmarshal(in, cipher)
if err != nil {
return nil, err
}
c1xBytes := bigIntTo32Bytes(cipher.X)
c1yBytes := bigIntTo32Bytes(cipher.Y)
c1xLen := len(c1xBytes)
c1yLen := len(c1yBytes)
c2Len := len(cipher.C2)
c3Len := len(cipher.C3)
result := make([]byte, 1+c1xLen+c1yLen+c2Len+c3Len)
pos := 0
result[pos] = UnCompress
pos += 1
copy(result[pos:pos+c1xLen], c1xBytes)
pos += c1xLen
copy(result[pos:pos+c1yLen], c1yBytes)
pos += c1yLen
copy(result[pos:pos+c3Len], cipher.C3)
pos += c3Len
copy(result[pos:pos+c2Len], cipher.C2)
return result, nil
} else {
return nil, errors.New("unknown cipherTextType:" + string(cipherTextType))
}
}
func getZ(digest hash.Hash, curve *P256V1Curve, pubX *big.Int, pubY *big.Int, userId []byte) []byte {
digest.Reset()
userIdLen := uint16(len(userId) * 8)
var userIdLenBytes [2]byte
binary.BigEndian.PutUint16(userIdLenBytes[:], userIdLen)
digest.Write(userIdLenBytes[:])
if userId != nil && len(userId) > 0 {
digest.Write(userId)
}
digest.Write(bigIntTo32Bytes(curve.A))
digest.Write(bigIntTo32Bytes(curve.B))
digest.Write(bigIntTo32Bytes(curve.Gx))
digest.Write(bigIntTo32Bytes(curve.Gy))
digest.Write(bigIntTo32Bytes(pubX))
digest.Write(bigIntTo32Bytes(pubY))
return digest.Sum(nil)
}
func calculateE(digest hash.Hash, curve *P256V1Curve, pubX *big.Int, pubY *big.Int, userId []byte, src []byte) *big.Int {
z := getZ(digest, curve, pubX, pubY, userId)
digest.Reset()
digest.Write(z)
digest.Write(src)
eHash := digest.Sum(nil)
return new(big.Int).SetBytes(eHash)
}
func MarshalSign(r, s *big.Int) ([]byte, error) {
result, err := asn1.Marshal(sm2Signature{r, s})
if err != nil {
return nil, err
}
return result, nil
}
func UnmarshalSign(sign []byte) (r, s *big.Int, err error) {
sm2Sign := new(sm2Signature)
_, err = asn1.Unmarshal(sign, sm2Sign)
if err != nil {
return nil, nil, err
}
return sm2Sign.R, sm2Sign.S, nil
}
func SignToRS(priv *PrivateKey, userId []byte, in []byte) (r, s *big.Int, err error) {
digest := sm3.New()
pubX, pubY := priv.Curve.ScalarBaseMult(priv.D.Bytes())
if userId == nil {
userId = sm2SignDefaultUserId
}
e := calculateE(digest, &priv.Curve, pubX, pubY, userId, in)
intZero := new(big.Int).SetInt64(0)
intOne := new(big.Int).SetInt64(1)
for {
var k *big.Int
var err error
for {
k, err = nextK(rand.Reader, priv.Curve.N)
if err != nil {
return nil, nil, err
}
px, _ := priv.Curve.ScalarBaseMult(k.Bytes())
r = util.Add(e, px)
r = util.Mod(r, priv.Curve.N)
rk := new(big.Int).Set(r)
rk = rk.Add(rk, k)
if r.Cmp(intZero) != 0 && rk.Cmp(priv.Curve.N) != 0 {
break
}
}
dPlus1ModN := util.Add(priv.D, intOne)
dPlus1ModN = util.ModInverse(dPlus1ModN, priv.Curve.N)
s = util.Mul(r, priv.D)
s = util.Sub(k, s)
s = util.Mod(s, priv.Curve.N)
s = util.Mul(dPlus1ModN, s)
s = util.Mod(s, priv.Curve.N)
if s.Cmp(intZero) != 0 {
break
}
}
return r, s, nil
}
// 签名结果为DER编码的字节数组
func Sign(priv *PrivateKey, userId []byte, in []byte) ([]byte, error) {
r, s, err := SignToRS(priv, userId, in)
if err != nil {
return nil, err
}
return MarshalSign(r, s)
}
func VerifyByRS(pub *PublicKey, userId []byte, src []byte, r, s *big.Int) bool {
intOne := new(big.Int).SetInt64(1)
if r.Cmp(intOne) == -1 || r.Cmp(pub.Curve.N) >= 0 {
return false
}
if s.Cmp(intOne) == -1 || s.Cmp(pub.Curve.N) >= 0 {
return false
}
digest := sm3.New()
if userId == nil {
userId = sm2SignDefaultUserId
}
e := calculateE(digest, &pub.Curve, pub.X, pub.Y, userId, src)
intZero := new(big.Int).SetInt64(0)
t := util.Add(r, s)
t = util.Mod(t, pub.Curve.N)
if t.Cmp(intZero) == 0 {
return false
}
sgx, sgy := pub.Curve.ScalarBaseMult(s.Bytes())
tpx, tpy := pub.Curve.ScalarMult(pub.X, pub.Y, t.Bytes())
x, y := pub.Curve.Add(sgx, sgy, tpx, tpy)
if util.IsEcPointInfinity(x, y) {
return false
}
expectedR := util.Add(e, x)
expectedR = util.Mod(expectedR, pub.Curve.N)
return expectedR.Cmp(r) == 0
}
// 输入签名须为DER编码的字节数组
func Verify(pub *PublicKey, userId []byte, src []byte, sign []byte) bool {
r, s, err := UnmarshalSign(sign)
if err != nil {
return false
}
return VerifyByRS(pub, userId, src, r, s)
}
================================================
FILE: sm2/sm2_loop_test.go
================================================
package sm2
import (
"crypto/rand"
"encoding/hex"
"fmt"
"math/big"
"testing"
)
const loopCount = 10
var loopTestSignData = []testSm2SignData{
{
d: "5DD701828C424B84C5D56770ECF7C4FE882E654CAC53C7CC89A66B1709068B9D",
x: "FF6712D3A7FC0D1B9E01FF471A87EA87525E47C7775039D19304E554DEFE0913",
y: "F632025F692776D4C13470ECA36AC85D560E794E1BCCF53D82C015988E0EB956",
in: "0102030405060708010203040506070801020304050607080102030405060708010203040506070801020304050607080102030405060708010203040506070830450220213C6CD6EBD6A4D5C2D0AB38E29D441836D1457A8118D34864C247D727831962022100D9248480342AC8513CCDF0F89A2250DC8F6EB4F2471E144E9A812E0AF497F801",
},
}
func TestSignVerifyLoop(t *testing.T) {
priv := new(PrivateKey)
priv.Curve = GetSm2P256V1()
dBytes, _ := hex.DecodeString(loopTestSignData[0].d)
priv.D = new(big.Int).SetBytes(dBytes)
pub := new(PublicKey)
pub.Curve = GetSm2P256V1()
xBytes, _ := hex.DecodeString(loopTestSignData[0].x)
yBytes, _ := hex.DecodeString(loopTestSignData[0].y)
pub.X = new(big.Int).SetBytes(xBytes)
pub.Y = new(big.Int).SetBytes(yBytes)
for i := 0; i < loopCount; i++ {
inBytes, _ := hex.DecodeString(loopTestSignData[0].in)
sign, err := Sign(priv, nil, inBytes)
if err != nil {
t.Error(err.Error())
break
}
result := Verify(pub, nil, inBytes, sign)
if !result {
t.Error("verify failed")
break
}
fmt.Printf("%d pass\n", i)
}
}
func TestSignVerifyLoop2(t *testing.T) {
for i := 0; i < loopCount; i++ {
priv, pub, err := GenerateKey(rand.Reader)
if err != nil {
t.Error(err.Error())
break
}
inBytes, _ := hex.DecodeString(loopTestSignData[0].in)
sign, err := Sign(priv, nil, inBytes)
if err != nil {
t.Error(err.Error())
break
}
result := Verify(pub, nil, inBytes, sign)
if !result {
t.Error("verify failed")
break
}
fmt.Printf("%d pass\n", i)
}
}
func TestSignVerifyLoop3(t *testing.T) {
priv, pub, err := GenerateKey(rand.Reader)
if err != nil {
t.Error(err.Error())
return
}
for i := 0; i < loopCount; i++ {
inBytes, _ := hex.DecodeString(loopTestSignData[0].in)
sign, err := Sign(priv, nil, inBytes)
if err != nil {
t.Error(err.Error())
break
}
result := Verify(pub, nil, inBytes, sign)
if !result {
t.Error("verify failed")
break
}
fmt.Printf("%d pass\n", i)
}
}
================================================
FILE: sm2/sm2_test.go
================================================
package sm2
import (
"bytes"
"crypto/rand"
"encoding/hex"
"fmt"
"math/big"
"testing"
)
func TestGetSm2P256V1(t *testing.T) {
curve := GetSm2P256V1()
fmt.Printf("P:%s\n", curve.Params().P.Text(16))
fmt.Printf("B:%s\n", curve.Params().B.Text(16))
fmt.Printf("N:%s\n", curve.Params().N.Text(16))
fmt.Printf("Gx:%s\n", curve.Params().Gx.Text(16))
fmt.Printf("Gy:%s\n", curve.Params().Gy.Text(16))
}
func TestGenerateKey(t *testing.T) {
priv, pub, err := GenerateKey(rand.Reader)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("priv:%s\n", priv.D.Text(16))
fmt.Printf("x:%s\n", pub.X.Text(16))
fmt.Printf("y:%s\n", pub.Y.Text(16))
curve := GetSm2P256V1()
if !curve.IsOnCurve(pub.X, pub.Y) {
t.Error("x,y is not on Curve")
return
}
fmt.Println("x,y is on sm2 Curve")
}
func TestEncryptDecrypt_C1C2C3(t *testing.T) {
src := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
priv, pub, err := GenerateKey(rand.Reader)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("d:%s\n", hex.EncodeToString(priv.D.Bytes()))
fmt.Printf("x:%s\n", hex.EncodeToString(pub.X.Bytes()))
fmt.Printf("y:%s\n", hex.EncodeToString(pub.Y.Bytes()))
cipherText, err := Encrypt(pub, src, C1C2C3)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("cipher text:%s\n", hex.EncodeToString(cipherText))
plainText, err := Decrypt(priv, cipherText, C1C2C3)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("plain text:%s\n", hex.EncodeToString(plainText))
if !bytes.Equal(plainText, src) {
t.Error("decrypt result not equal expected")
return
}
}
func TestEncryptDecrypt_C1C3C2(t *testing.T) {
src := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
priv, pub, err := GenerateKey(rand.Reader)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("d:%s\n", hex.EncodeToString(priv.D.Bytes()))
fmt.Printf("x:%s\n", hex.EncodeToString(pub.X.Bytes()))
fmt.Printf("y:%s\n", hex.EncodeToString(pub.Y.Bytes()))
cipherText, err := Encrypt(pub, src, C1C3C2)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("cipher text:%s\n", hex.EncodeToString(cipherText))
plainText, err := Decrypt(priv, cipherText, C1C3C2)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("plain text:%s\n", hex.EncodeToString(plainText))
if !bytes.Equal(plainText, src) {
t.Error("decrypt result not equal expected")
return
}
}
func TestCipherDerEncode_C1C2C3(t *testing.T) {
src := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
priv, pub, err := GenerateKey(rand.Reader)
if err != nil {
t.Error(err.Error())
return
}
cipherText, err := Encrypt(pub, src, C1C2C3)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("before DER encode, cipher text:%s\n", hex.EncodeToString(cipherText))
derCipher, err := MarshalCipher(cipherText, C1C2C3)
if err != nil {
t.Error(err.Error())
return
}
//err = ioutil.WriteFile("derCipher.dat", derCipher, 0644)
//if err != nil {
// t.Error(err.Error())
// return
//}
cipherText, err = UnmarshalCipher(derCipher, C1C2C3)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("after DER decode, cipher text:%s\n", hex.EncodeToString(cipherText))
plainText, err := Decrypt(priv, cipherText, C1C2C3)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("plain text:%s\n", hex.EncodeToString(plainText))
if !bytes.Equal(plainText, src) {
t.Error("decrypt result not equal expected")
return
}
}
func TestCipherDerEncode_C1C3C2(t *testing.T) {
src := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
priv, pub, err := GenerateKey(rand.Reader)
if err != nil {
t.Error(err.Error())
return
}
cipherText, err := Encrypt(pub, src, C1C3C2)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("before DER encode, cipher text:%s\n", hex.EncodeToString(cipherText))
derCipher, err := MarshalCipher(cipherText, C1C3C2)
if err != nil {
t.Error(err.Error())
return
}
//err = ioutil.WriteFile("derCipher.dat", derCipher, 0644)
//if err != nil {
// t.Error(err.Error())
// return
//}
cipherText, err = UnmarshalCipher(derCipher, C1C3C2)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("after DER decode, cipher text:%s\n", hex.EncodeToString(cipherText))
plainText, err := Decrypt(priv, cipherText, C1C3C2)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("plain text:%s\n", hex.EncodeToString(plainText))
if !bytes.Equal(plainText, src) {
t.Error("decrypt result not equal expected")
return
}
}
type testSm2SignData struct {
d string
x string
y string
in string
sign string
}
var testSignData = []testSm2SignData{
{
d: "5DD701828C424B84C5D56770ECF7C4FE882E654CAC53C7CC89A66B1709068B9D",
x: "FF6712D3A7FC0D1B9E01FF471A87EA87525E47C7775039D19304E554DEFE0913",
y: "F632025F692776D4C13470ECA36AC85D560E794E1BCCF53D82C015988E0EB956",
in: "0102030405060708010203040506070801020304050607080102030405060708",
sign: "30450220213C6CD6EBD6A4D5C2D0AB38E29D441836D1457A8118D34864C247D727831962022100D9248480342AC8513CCDF0F89A2250DC8F6EB4F2471E144E9A812E0AF497F801",
},
}
func TestSign(t *testing.T) {
for _, data := range testSignData {
priv := new(PrivateKey)
priv.Curve = GetSm2P256V1()
dBytes, _ := hex.DecodeString(data.d)
priv.D = new(big.Int).SetBytes(dBytes)
inBytes, _ := hex.DecodeString(data.in)
sign, err := Sign(priv, nil, inBytes)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("sign:%s\n", hex.EncodeToString(sign))
pub := new(PublicKey)
pub.Curve = GetSm2P256V1()
xBytes, _ := hex.DecodeString(data.x)
yBytes, _ := hex.DecodeString(data.y)
pub.X = new(big.Int).SetBytes(xBytes)
pub.Y = new(big.Int).SetBytes(yBytes)
result := Verify(pub, nil, inBytes, sign)
if !result {
t.Error("verify failed")
return
}
}
}
func TestVerify(t *testing.T) {
for _, data := range testSignData {
pub := new(PublicKey)
pub.Curve = GetSm2P256V1()
xBytes, _ := hex.DecodeString(data.x)
yBytes, _ := hex.DecodeString(data.y)
pub.X = new(big.Int).SetBytes(xBytes)
pub.Y = new(big.Int).SetBytes(yBytes)
inBytes, _ := hex.DecodeString(data.in)
sign, _ := hex.DecodeString(data.sign)
result := Verify(pub, nil, inBytes, sign)
if !result {
t.Error("verify failed")
return
}
}
}
================================================
FILE: sm3/sm3.go
================================================
package sm3
import (
"encoding/binary"
"fmt"
"hash"
"math/bits"
)
const (
DigestLength = 32
BlockSize = 16
)
var gT = []uint32{
0x79CC4519, 0xF3988A32, 0xE7311465, 0xCE6228CB, 0x9CC45197, 0x3988A32F, 0x7311465E, 0xE6228CBC,
0xCC451979, 0x988A32F3, 0x311465E7, 0x6228CBCE, 0xC451979C, 0x88A32F39, 0x11465E73, 0x228CBCE6,
0x9D8A7A87, 0x3B14F50F, 0x7629EA1E, 0xEC53D43C, 0xD8A7A879, 0xB14F50F3, 0x629EA1E7, 0xC53D43CE,
0x8A7A879D, 0x14F50F3B, 0x29EA1E76, 0x53D43CEC, 0xA7A879D8, 0x4F50F3B1, 0x9EA1E762, 0x3D43CEC5,
0x7A879D8A, 0xF50F3B14, 0xEA1E7629, 0xD43CEC53, 0xA879D8A7, 0x50F3B14F, 0xA1E7629E, 0x43CEC53D,
0x879D8A7A, 0x0F3B14F5, 0x1E7629EA, 0x3CEC53D4, 0x79D8A7A8, 0xF3B14F50, 0xE7629EA1, 0xCEC53D43,
0x9D8A7A87, 0x3B14F50F, 0x7629EA1E, 0xEC53D43C, 0xD8A7A879, 0xB14F50F3, 0x629EA1E7, 0xC53D43CE,
0x8A7A879D, 0x14F50F3B, 0x29EA1E76, 0x53D43CEC, 0xA7A879D8, 0x4F50F3B1, 0x9EA1E762, 0x3D43CEC5}
type sm3Digest struct {
v [DigestLength / 4]uint32
inWords [BlockSize]uint32
xOff int32
w [68]uint32
xBuf [4]byte
xBufOff int32
byteCount int64
}
func New() hash.Hash {
digest := new(sm3Digest)
digest.Reset()
return digest
}
func (digest *sm3Digest) Sum(b []byte) []byte {
d1 := digest
h := d1.checkSum()
return append(b, h[:]...)
}
// Size returns the number of bytes Sum will return.
func (digest *sm3Digest) Size() int {
return DigestLength
}
// BlockSize returns the hash's underlying block size.
// The Write method must be able to accept any amount
// of data, but it may operate more efficiently if all writes
// are a multiple of the block size.
func (digest *sm3Digest) BlockSize() int {
return BlockSize
}
func (digest *sm3Digest) Reset() {
digest.byteCount = 0
digest.xBufOff = 0
for i := 0; i < len(digest.xBuf); i++ {
digest.xBuf[i] = 0
}
for i := 0; i < len(digest.inWords); i++ {
digest.inWords[i] = 0
}
for i := 0; i < len(digest.w); i++ {
digest.w[i] = 0
}
digest.v[0] = 0x7380166F
digest.v[1] = 0x4914B2B9
digest.v[2] = 0x172442D7
digest.v[3] = 0xDA8A0600
digest.v[4] = 0xA96F30BC
digest.v[5] = 0x163138AA
digest.v[6] = 0xE38DEE4D
digest.v[7] = 0xB0FB0E4E
digest.xOff = 0
}
func (digest *sm3Digest) Write(p []byte) (n int, err error) {
_ = p[0]
inLen := len(p)
i := 0
if digest.xBufOff != 0 {
for i < inLen {
digest.xBuf[digest.xBufOff] = p[i]
digest.xBufOff++
i++
if digest.xBufOff == 4 {
digest.processWord(digest.xBuf[:], 0)
digest.xBufOff = 0
break
}
}
}
limit := ((inLen - i) & ^3) + i
for ; i < limit; i += 4 {
digest.processWord(p, int32(i))
}
for i < inLen {
digest.xBuf[digest.xBufOff] = p[i]
digest.xBufOff++
i++
}
digest.byteCount += int64(inLen)
n = inLen
return
}
func (digest *sm3Digest) finish() {
bitLength := digest.byteCount << 3
digest.Write([]byte{128})
for digest.xBufOff != 0 {
digest.Write([]byte{0})
}
digest.processLength(bitLength)
digest.processBlock()
}
func (digest *sm3Digest) checkSum() [DigestLength]byte {
digest.finish()
vlen := len(digest.v)
var out [DigestLength]byte
for i := 0; i < vlen; i++ {
binary.BigEndian.PutUint32(out[i*4:(i+1)*4], digest.v[i])
}
return out
}
func (digest *sm3Digest) processBlock() {
for j := 0; j < 16; j++ {
digest.w[j] = digest.inWords[j]
}
for j := 16; j < 68; j++ {
wj3 := digest.w[j-3]
r15 := (wj3 << 15) | (wj3 >> (32 - 15))
wj13 := digest.w[j-13]
r7 := (wj13 << 7) | (wj13 >> (32 - 7))
digest.w[j] = p1(digest.w[j-16]^digest.w[j-9]^r15) ^ r7 ^ digest.w[j-6]
}
A := digest.v[0]
B := digest.v[1]
C := digest.v[2]
D := digest.v[3]
E := digest.v[4]
F := digest.v[5]
G := digest.v[6]
H := digest.v[7]
for j := 0; j < 16; j++ {
a12 := (A << 12) | (A >> (32 - 12))
s1 := a12 + E + gT[j]
SS1 := (s1 << 7) | (s1 >> (32 - 7))
SS2 := SS1 ^ a12
Wj := digest.w[j]
W1j := Wj ^ digest.w[j+4]
TT1 := ff0(A, B, C) + D + SS2 + W1j
TT2 := gg0(E, F, G) + H + SS1 + Wj
D = C
C = (B << 9) | (B >> (32 - 9))
B = A
A = TT1
H = G
G = (F << 19) | (F >> (32 - 19))
F = E
E = p0(TT2)
}
for j := 16; j < 64; j++ {
a12 := (A << 12) | (A >> (32 - 12))
s1 := a12 + E + gT[j]
SS1 := (s1 << 7) | (s1 >> (32 - 7))
SS2 := SS1 ^ a12
Wj := digest.w[j]
W1j := Wj ^ digest.w[j+4]
TT1 := ff1(A, B, C) + D + SS2 + W1j
TT2 := gg1(E, F, G) + H + SS1 + Wj
D = C
C = (B << 9) | (B >> (32 - 9))
B = A
A = TT1
H = G
G = (F << 19) | (F >> (32 - 19))
F = E
E = p0(TT2)
}
digest.v[0] ^= A
digest.v[1] ^= B
digest.v[2] ^= C
digest.v[3] ^= D
digest.v[4] ^= E
digest.v[5] ^= F
digest.v[6] ^= G
digest.v[7] ^= H
digest.xOff = 0
}
func (digest *sm3Digest) processWord(in []byte, inOff int32) {
n := binary.BigEndian.Uint32(in[inOff : inOff+4])
digest.inWords[digest.xOff] = n
digest.xOff++
if digest.xOff >= 16 {
digest.processBlock()
}
}
func (digest *sm3Digest) processLength(bitLength int64) {
if digest.xOff > (BlockSize - 2) {
digest.inWords[digest.xOff] = 0
digest.xOff++
digest.processBlock()
}
for ; digest.xOff < (BlockSize - 2); digest.xOff++ {
digest.inWords[digest.xOff] = 0
}
digest.inWords[digest.xOff] = uint32(bitLength >> 32)
digest.xOff++
digest.inWords[digest.xOff] = uint32(bitLength)
digest.xOff++
}
func p0(x uint32) uint32 {
r9 := bits.RotateLeft32(x, 9)
r17 := bits.RotateLeft32(x, 17)
return x ^ r9 ^ r17
}
func p1(x uint32) uint32 {
r15 := bits.RotateLeft32(x, 15)
r23 := bits.RotateLeft32(x, 23)
return x ^ r15 ^ r23
}
func ff0(x uint32, y uint32, z uint32) uint32 {
return x ^ y ^ z
}
func ff1(x uint32, y uint32, z uint32) uint32 {
return (x & y) | (x & z) | (y & z)
}
func gg0(x uint32, y uint32, z uint32) uint32 {
return x ^ y ^ z
}
func gg1(x uint32, y uint32, z uint32) uint32 {
return (x & y) | ((^x) & z)
}
func Sum(data []byte) [DigestLength]byte {
var d sm3Digest
d.Reset()
d.Write(data)
return d.checkSum()
}
func PrintT() {
var T [64]uint32
fmt.Print("{")
for j := 0; j < 16; j++ {
T[j] = 0x79CC4519
Tj := (T[j] << uint32(j)) | (T[j] >> (32 - uint32(j)))
fmt.Printf("0x%08X, ", Tj)
}
for j := 16; j < 64; j++ {
n := j % 32
T[j] = 0x7A879D8A
Tj := (T[j] << uint32(n)) | (T[j] >> (32 - uint32(n)))
if j == 63 {
fmt.Printf("0x%08X}\n", Tj)
} else {
fmt.Printf("0x%08X, ", Tj)
}
}
}
================================================
FILE: sm3/sm3_test.go
================================================
package sm3
import (
"bytes"
"encoding/hex"
"fmt"
"testing"
)
var testData = map[string]string{
"abc": "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0",
"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd": "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732"}
func TestPrintT(t *testing.T) {
PrintT()
}
func TestSum(t *testing.T) {
for src, expected := range testData {
testSum(t, src, expected)
}
}
func TestSm3Digest_Sum(t *testing.T) {
for src, expected := range testData {
testSm3DigestSum(t, src, expected)
}
}
func testSum(t *testing.T, src string, expected string) {
hash := Sum([]byte(src))
hashHex := hex.EncodeToString(hash[:])
if hashHex != expected {
t.Errorf("result:%s , not equal expected\n", hashHex)
return
}
}
func testSm3DigestSum(t *testing.T, src string, expected string) {
d := New()
d.Write([]byte(src))
hash := d.Sum(nil)
hashHex := hex.EncodeToString(hash[:])
if hashHex != expected {
t.Errorf("result:%s , not equal expected\n", hashHex)
return
}
}
func TestSm3Digest_Write(t *testing.T) {
src1 := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
src2 := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
src3 := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
d := New()
d.Write(src1)
d.Write(src2)
d.Write(src3)
digest1 := d.Sum(nil)
fmt.Printf("1 : %s\n", hex.EncodeToString(digest1))
d.Reset()
d.Write(src1)
d.Write(src2)
d.Write(src3)
digest2 := d.Sum(nil)
fmt.Printf("2 : %s\n", hex.EncodeToString(digest2))
if !bytes.Equal(digest1, digest2) {
t.Error("")
return
}
}
================================================
FILE: sm4/sm4.go
================================================
package sm4
import (
"crypto/cipher"
"encoding/binary"
"errors"
"math/bits"
"strconv"
)
const (
BlockSize = 16
KeySize = 16
)
var sBox = [256]byte{
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7,
0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3,
0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a,
0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95,
0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba,
0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b,
0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2,
0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,
0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5,
0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55,
0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60,
0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f,
0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f,
0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd,
0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e,
0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20,
0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
}
var cK = [32]uint32{
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279,
}
var fK = [4]uint32{
0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc,
}
type KeySizeError int
func (k KeySizeError) Error() string {
return "sm4: invalid key size " + strconv.Itoa(int(k))
}
type sm4Cipher struct {
enc []uint32
dec []uint32
}
func NewCipher(key []byte) (cipher.Block, error) {
n := len(key)
if n != KeySize {
return nil, KeySizeError(n)
}
c := new(sm4Cipher)
c.enc = expandKey(key, true)
c.dec = expandKey(key, false)
return c, nil
}
func (c *sm4Cipher) BlockSize() int {
return BlockSize
}
func (c *sm4Cipher) Encrypt(dst, src []byte) {
if len(src) < BlockSize {
panic("sm4: input not full block")
}
if len(dst) < BlockSize {
panic("sm4: output not full block")
}
processBlock(c.enc, src, dst)
}
func (c *sm4Cipher) Decrypt(dst, src []byte) {
if len(src) < BlockSize {
panic("sm4: input not full block")
}
if len(dst) < BlockSize {
panic("sm4: output not full block")
}
processBlock(c.dec, src, dst)
}
func expandKey(key []byte, forEnc bool) []uint32 {
var mK [4]uint32
mK[0] = binary.BigEndian.Uint32(key[0:4])
mK[1] = binary.BigEndian.Uint32(key[4:8])
mK[2] = binary.BigEndian.Uint32(key[8:12])
mK[3] = binary.BigEndian.Uint32(key[12:16])
var x [5]uint32
x[0] = mK[0] ^ fK[0]
x[1] = mK[1] ^ fK[1]
x[2] = mK[2] ^ fK[2]
x[3] = mK[3] ^ fK[3]
var rk [32]uint32
if forEnc {
for i := 0; i < 32; i++ {
x[(i+4)%5] = encRound(x[i%5], x[(i+1)%5], x[(i+2)%5], x[(i+3)%5], x[(i+4)%5], rk[:], i)
}
} else {
for i := 0; i < 32; i++ {
x[(i+4)%5] = decRound(x[i%5], x[(i+1)%5], x[(i+2)%5], x[(i+3)%5], x[(i+4)%5], rk[:], i)
}
}
return rk[:]
}
func tau(a uint32) uint32 {
var aArr [4]byte
var bArr [4]byte
binary.BigEndian.PutUint32(aArr[:], a)
bArr[0] = sBox[aArr[0]]
bArr[1] = sBox[aArr[1]]
bArr[2] = sBox[aArr[2]]
bArr[3] = sBox[aArr[3]]
return binary.BigEndian.Uint32(bArr[:])
}
func lAp(b uint32) uint32 {
return b ^ bits.RotateLeft32(b, 13) ^ bits.RotateLeft32(b, 23)
}
func tAp(z uint32) uint32 {
return lAp(tau(z))
}
func encRound(x0 uint32, x1 uint32, x2 uint32, x3 uint32, x4 uint32, rk []uint32, i int) uint32 {
x4 = x0 ^ tAp(x1^x2^x3^cK[i])
rk[i] = x4
return x4
}
func decRound(x0 uint32, x1 uint32, x2 uint32, x3 uint32, x4 uint32, rk []uint32, i int) uint32 {
x4 = x0 ^ tAp(x1^x2^x3^cK[i])
rk[31-i] = x4
return x4
}
func processBlock(rk []uint32, in []byte, out []byte) {
var x [BlockSize / 4]uint32
x[0] = binary.BigEndian.Uint32(in[0:4])
x[1] = binary.BigEndian.Uint32(in[4:8])
x[2] = binary.BigEndian.Uint32(in[8:12])
x[3] = binary.BigEndian.Uint32(in[12:16])
for i := 0; i < 32; i += 4 {
x[0] = f0(x[:], rk[i])
x[1] = f1(x[:], rk[i+1])
x[2] = f2(x[:], rk[i+2])
x[3] = f3(x[:], rk[i+3])
}
r(x[:])
binary.BigEndian.PutUint32(out[0:4], x[0])
binary.BigEndian.PutUint32(out[4:8], x[1])
binary.BigEndian.PutUint32(out[8:12], x[2])
binary.BigEndian.PutUint32(out[12:16], x[3])
}
func l(b uint32) uint32 {
return b ^ bits.RotateLeft32(b, 2) ^ bits.RotateLeft32(b, 10) ^
bits.RotateLeft32(b, 18) ^ bits.RotateLeft32(b, 24)
}
func t(z uint32) uint32 {
return l(tau(z))
}
func r(a []uint32) {
a[0] = a[0] ^ a[3]
a[3] = a[0] ^ a[3]
a[0] = a[0] ^ a[3]
a[1] = a[1] ^ a[2]
a[2] = a[1] ^ a[2]
a[1] = a[1] ^ a[2]
}
func f0(x []uint32, rk uint32) uint32 {
return x[0] ^ t(x[1]^x[2]^x[3]^rk)
}
func f1(x []uint32, rk uint32) uint32 {
return x[1] ^ t(x[2]^x[3]^x[0]^rk)
}
func f2(x []uint32, rk uint32) uint32 {
return x[2] ^ t(x[3]^x[0]^x[1]^rk)
}
func f3(x []uint32, rk uint32) uint32 {
return x[3] ^ t(x[0]^x[1]^x[2]^rk)
}
// 输入的plainText长度必须是BlockSize(16)的整数倍,也就是调用该方法前调用方需先加好padding,
// 可调用util.PKCS5Padding()方法进行加padding操作
func ECBEncrypt(key, plainText []byte) (cipherText []byte, err error) {
plainTextLen := len(plainText)
if plainTextLen%BlockSize != 0 {
return nil, errors.New("input not full blocks")
}
c, err := NewCipher(key)
if err != nil {
return nil, err
}
cipherText = make([]byte, plainTextLen)
for i := 0; i < plainTextLen; i += BlockSize {
c.Encrypt(cipherText[i:i+BlockSize], plainText[i:i+BlockSize])
}
return cipherText, nil
}
// 输出的plainText是加padding的明文,调用方需要自己去padding,
// 可调用util.PKCS5UnPadding()方法进行去padding操作
func ECBDecrypt(key, cipherText []byte) (plainText []byte, err error) {
cipherTextLen := len(cipherText)
if cipherTextLen%BlockSize != 0 {
return nil, errors.New("input not full blocks")
}
c, err := NewCipher(key)
if err != nil {
return nil, err
}
plainText = make([]byte, cipherTextLen)
for i := 0; i < cipherTextLen; i += BlockSize {
c.Decrypt(plainText[i:i+BlockSize], cipherText[i:i+BlockSize])
}
return plainText, nil
}
// 输入的plainText长度必须是BlockSize(16)的整数倍,也就是调用该方法前调用方需先加好padding,
// 可调用util.PKCS5Padding()方法进行加padding操作
func CBCEncrypt(key, iv, plainText []byte) (cipherText []byte, err error) {
plainTextLen := len(plainText)
if plainTextLen%BlockSize != 0 {
return nil, errors.New("input not full blocks")
}
c, err := NewCipher(key)
if err != nil {
return nil, err
}
encrypter := cipher.NewCBCEncrypter(c, iv)
cipherText = make([]byte, plainTextLen)
encrypter.CryptBlocks(cipherText, plainText)
return cipherText, nil
}
// 输出的plainText是加padding的明文,调用方需要自己去padding,
// 可调用util.PKCS5UnPadding()方法进行去padding操作
func CBCDecrypt(key, iv, cipherText []byte) (plainText []byte, err error) {
cipherTextLen := len(cipherText)
if cipherTextLen%BlockSize != 0 {
return nil, errors.New("input not full blocks")
}
c, err := NewCipher(key)
if err != nil {
return nil, err
}
decrypter := cipher.NewCBCDecrypter(c, iv)
plainText = make([]byte, len(cipherText))
decrypter.CryptBlocks(plainText, cipherText)
return plainText, nil
}
================================================
FILE: sm4/sm4_test.go
================================================
package sm4
import (
"bytes"
"encoding/hex"
"fmt"
"github.com/ZZMarquis/gm/util"
"testing"
)
type sm4CbcTestData struct {
key []byte
iv []byte
in []byte
out []byte
}
var cbcTestData = []sm4CbcTestData{
{
key: []byte{0x7b, 0xea, 0x0a, 0xa5, 0x45, 0x8e, 0xd1, 0xa3, 0x7d, 0xb1, 0x65, 0x2e, 0xfb, 0xc5, 0x95, 0x05},
iv: []byte{0x70, 0xb6, 0xe0, 0x8d, 0x46, 0xee, 0x82, 0x24, 0x45, 0x60, 0x0b, 0x25, 0xc4, 0x71, 0xfa, 0xba},
in: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
out: []byte{0xca, 0x55, 0xc5, 0x15, 0x0b, 0xf7, 0xf4, 0x6f, 0xc9, 0x89, 0x2a, 0xce, 0x49, 0x78, 0x93, 0x03},
},
{
key: []byte{0x7b, 0xea, 0x0a, 0xa5, 0x45, 0x8e, 0xd1, 0xa3, 0x7d, 0xb1, 0x65, 0x2e, 0xfb, 0xc5, 0x95, 0x05},
iv: []byte{0x70, 0xb6, 0xe0, 0x8d, 0x46, 0xee, 0x82, 0x24, 0x45, 0x60, 0x0b, 0x25, 0xc4, 0x71, 0xfa, 0xba},
in: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
out: []byte{0x95, 0xe1, 0xec, 0x3b, 0x56, 0x4a, 0x46, 0x71, 0xe7, 0xd6, 0xb1, 0x10, 0xe9, 0x09, 0x0b, 0x1b, 0xb7, 0xb5, 0x9e, 0x8d, 0x74, 0x47, 0x1e, 0x70, 0x86, 0x04, 0x6b, 0xe8, 0x78, 0x00, 0x45, 0x32},
},
}
func TestSm4_CBC_Encrypt(t *testing.T) {
for _, data := range cbcTestData {
fmt.Printf("Key:%s\n", hex.EncodeToString(data.key))
fmt.Printf("IV:%s\n", hex.EncodeToString(data.iv))
cipherText, err := CBCEncrypt(data.key, data.iv, util.PKCS5Padding(data.in, BlockSize))
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("encrypt cipherText:%s\n", hex.EncodeToString(cipherText))
if !bytes.Equal(cipherText, data.out) {
t.Error("encrypt cipherText not equal expected")
return
}
plainTextWithPadding, err := CBCDecrypt(data.key, data.iv, cipherText)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("decrypt cipherText:%s\n", hex.EncodeToString(plainTextWithPadding))
plainText := util.PKCS5UnPadding(plainTextWithPadding)
if !bytes.Equal(plainText, data.in) {
t.Error("decrypt cipherText not equal expected")
return
}
}
}
type sm4EcbTestData struct {
key []byte
in []byte
}
var ecbTestData = []sm4EcbTestData{
{
key: []byte("1234567890123456"),
in: []byte("ssssssss"),
}, {
key: []byte("1234567890123456"),
in: []byte("ssssssssssssssss"),
}, {
key: []byte("1234567890123456"),
in: []byte("ssssssssssssssssssssssss"),
},
}
func TestSm4_ECB_Encrypt_PKCS5Padding(t *testing.T) {
for _, testData := range ecbTestData {
plainTextWithPadding := util.PKCS5Padding(testData.in, BlockSize)
cipherText, err := ECBEncrypt(testData.key, plainTextWithPadding)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("%x\n", cipherText)
plainTextWithPadding, err = ECBDecrypt(testData.key, cipherText)
if err != nil {
t.Error(err.Error())
return
}
plainText := util.PKCS5UnPadding(plainTextWithPadding)
fmt.Println(string(plainText))
if !bytes.Equal(testData.in, plainText) {
t.Error("decrypt result not equal expected")
return
}
}
}
func TestSm4_ECB_Encrypt_ZeroPadding(t *testing.T) {
for _, testData := range ecbTestData {
plainTextWithPadding := util.ZeroPadding(testData.in, BlockSize)
paddingLen := len(plainTextWithPadding) - len(testData.in)
cipherText, err := ECBEncrypt(testData.key, plainTextWithPadding)
if err != nil {
t.Error(err.Error())
return
}
fmt.Printf("%x\n", cipherText)
plainTextWithPadding, err = ECBDecrypt(testData.key, cipherText)
if err != nil {
t.Error(err.Error())
return
}
plainText := util.UnZeroPadding(plainTextWithPadding, paddingLen)
fmt.Println(string(plainText))
if !bytes.Equal(testData.in, plainText) {
t.Error("decrypt result not equal expected")
return
}
}
}
================================================
FILE: util/bigint.go
================================================
package util
import "math/big"
func Add(x, y *big.Int) *big.Int {
var z big.Int
z.Add(x, y)
return &z
}
func Sub(x, y *big.Int) *big.Int {
var z big.Int
z.Sub(x, y)
return &z
}
func Mod(x, y *big.Int) *big.Int {
var z big.Int
z.Mod(x, y)
return &z
}
func ModInverse(x, y *big.Int) *big.Int {
var z big.Int
z.ModInverse(x, y)
return &z
}
func Mul(x, y *big.Int) *big.Int {
var z big.Int
z.Mul(x, y)
return &z
}
func Lsh(x *big.Int, n uint) *big.Int {
var z big.Int
z.Lsh(x, n)
return &z
}
func SetBit(x *big.Int, i int, b uint) *big.Int {
var z big.Int
z.SetBit(x, i, b)
return &z
}
func And(x, y *big.Int) *big.Int {
var z big.Int
z.And(x, y)
return &z
}
================================================
FILE: util/bigint_test.go
================================================
package util
import (
"fmt"
"math/big"
"testing"
)
func TestAdd(t *testing.T) {
a := new(big.Int).SetInt64(1)
b := new(big.Int).SetInt64(1)
a.Add(a, b)
fmt.Printf("a:%s\n", a.Text(10))
fmt.Printf("b:%s\n", b.Text(10))
}
func TestAdd2(t *testing.T) {
a := new(big.Int).SetInt64(1)
b := new(big.Int).SetInt64(1)
z := Add(a, b)
fmt.Printf("a:%s\n", a.Text(10))
fmt.Printf("b:%s\n", b.Text(10))
fmt.Printf("z:%s\n", z.Text(10))
}
================================================
FILE: util/ec.go
================================================
package util
import "math/big"
func IsEcPointInfinity(x, y *big.Int) bool {
if x.Sign() == 0 && y.Sign() == 0 {
return true
}
return false
}
func ZForAffine(x, y *big.Int) *big.Int {
z := new(big.Int)
if x.Sign() != 0 || y.Sign() != 0 {
z.SetInt64(1)
}
return z
}
================================================
FILE: util/padding.go
================================================
package util
import "bytes"
func PKCS5Padding(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(src, padtext...)
}
func PKCS5UnPadding(src []byte) []byte {
length := len(src)
unpadding := int(src[length-1])
return src[:(length - unpadding)]
}
func ZeroPadding(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padtext := bytes.Repeat([]byte{0}, padding)
return append(src, padtext...)
}
// UnZeroPadding
// 由于原文最后一个或若干个字节就有可能为0,所以大多情况下不能简单粗暴地后面有几个0就去掉几个0,除非可以确定最后一个字节肯定不为0.
// 所以需要用户自己去指定具体要去掉末尾几个字节,具体要看用户的自己的数据协议怎么设计。
func UnZeroPadding(src []byte, paddingLen int) []byte {
return src[:len(src)-paddingLen]
}
gitextract_meawgwxy/
├── .github/
│ └── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── cryptobyte/
│ ├── README
│ ├── asn1/
│ │ └── asn1.go
│ ├── asn1.go
│ ├── builder.go
│ └── string.go
├── go.mod
├── sm2/
│ ├── cert/
│ │ ├── gmx509.go
│ │ └── gmx509_test.go
│ ├── keyexchange.go
│ ├── keyexchange_test.go
│ ├── sm2.go
│ ├── sm2_loop_test.go
│ └── sm2_test.go
├── sm3/
│ ├── sm3.go
│ └── sm3_test.go
├── sm4/
│ ├── sm4.go
│ └── sm4_test.go
└── util/
├── bigint.go
├── bigint_test.go
├── ec.go
└── padding.go
SYMBOL INDEX (292 symbols across 19 files)
FILE: cryptobyte/asn1.go
method AddASN1Int64 (line 22) | func (b *Builder) AddASN1Int64(v int64) {
method AddASN1Enum (line 27) | func (b *Builder) AddASN1Enum(v int64) {
method addASN1Signed (line 31) | func (b *Builder) addASN1Signed(tag asn1.Tag, v int64) {
method AddASN1Uint64 (line 46) | func (b *Builder) AddASN1Uint64(v uint64) {
method AddASN1BigInt (line 61) | func (b *Builder) AddASN1BigInt(n *big.Int) {
method AddASN1OctetString (line 95) | func (b *Builder) AddASN1OctetString(bytes []byte) {
constant generalizedTimeFormatStr (line 101) | generalizedTimeFormatStr = "20060102150405Z0700"
method AddASN1GeneralizedTime (line 104) | func (b *Builder) AddASN1GeneralizedTime(t time.Time) {
method AddASN1BitString (line 116) | func (b *Builder) AddASN1BitString(data []byte) {
method addBase128Int (line 123) | func (b *Builder) addBase128Int(n int64) {
function isValidOID (line 144) | func isValidOID(oid encoding_asn1.ObjectIdentifier) bool {
method AddASN1ObjectIdentifier (line 162) | func (b *Builder) AddASN1ObjectIdentifier(oid encoding_asn1.ObjectIdenti...
method AddASN1Boolean (line 176) | func (b *Builder) AddASN1Boolean(v bool) {
method AddASN1NULL (line 186) | func (b *Builder) AddASN1NULL() {
method MarshalASN1 (line 192) | func (b *Builder) MarshalASN1(v interface{}) {
method AddASN1 (line 211) | func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) {
method ReadASN1Boolean (line 227) | func (s *String) ReadASN1Boolean(out *bool) bool {
method ReadASN1Integer (line 250) | func (s *String) ReadASN1Integer(out interface{}) bool {
function checkASN1Integer (line 277) | func checkASN1Integer(bytes []byte) bool {
method readASN1BigInt (line 294) | func (s *String) readASN1BigInt(out *big.Int) bool {
method readASN1Int64 (line 314) | func (s *String) readASN1Int64(out *int64) bool {
function asn1Signed (line 322) | func asn1Signed(out *int64, n []byte) bool {
method readASN1Uint64 (line 337) | func (s *String) readASN1Uint64(out *uint64) bool {
function asn1Unsigned (line 345) | func asn1Unsigned(out *uint64, n []byte) bool {
method ReadASN1Enum (line 364) | func (s *String) ReadASN1Enum(out *int) bool {
method readBase128Int (line 377) | func (s *String) readBase128Int(out *int) bool {
method ReadASN1ObjectIdentifier (line 396) | func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdent...
method ReadASN1GeneralizedTime (line 435) | func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
method ReadASN1BitString (line 454) | func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool {
method ReadASN1BitStringAsBytes (line 476) | func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool {
method ReadASN1Bytes (line 493) | func (s *String) ReadASN1Bytes(out *[]byte, tag asn1.Tag) bool {
method ReadASN1 (line 502) | func (s *String) ReadASN1(out *String, tag asn1.Tag) bool {
method ReadASN1Element (line 515) | func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool {
method ReadAnyASN1 (line 528) | func (s *String) ReadAnyASN1(out *String, outTag *asn1.Tag) bool {
method ReadAnyASN1Element (line 537) | func (s *String) ReadAnyASN1Element(out *String, outTag *asn1.Tag) bool {
method PeekASN1Tag (line 543) | func (s String) PeekASN1Tag(tag asn1.Tag) bool {
method SkipASN1 (line 551) | func (s *String) SkipASN1(tag asn1.Tag) bool {
method ReadOptionalASN1 (line 560) | func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn...
method SkipOptionalASN1 (line 573) | func (s *String) SkipOptionalASN1(tag asn1.Tag) bool {
method ReadOptionalASN1Integer (line 586) | func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, ...
method ReadOptionalASN1OctetString (line 624) | func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bo...
method ReadOptionalASN1Boolean (line 647) | func (s *String) ReadOptionalASN1Boolean(out *bool, defaultValue bool) b...
method readASN1 (line 662) | func (s *String) readASN1(out *String, outTag *asn1.Tag, skipHeader bool...
FILE: cryptobyte/asn1/asn1.go
type Tag (line 15) | type Tag
method Constructed (line 23) | func (t Tag) Constructed() Tag { return t | classConstructed }
method ContextSpecific (line 26) | func (t Tag) ContextSpecific() Tag { return t | classContextSpecific }
constant classConstructed (line 18) | classConstructed = 0x20
constant classContextSpecific (line 19) | classContextSpecific = 0x80
constant BOOLEAN (line 30) | BOOLEAN = Tag(1)
constant INTEGER (line 31) | INTEGER = Tag(2)
constant BIT_STRING (line 32) | BIT_STRING = Tag(3)
constant OCTET_STRING (line 33) | OCTET_STRING = Tag(4)
constant NULL (line 34) | NULL = Tag(5)
constant OBJECT_IDENTIFIER (line 35) | OBJECT_IDENTIFIER = Tag(6)
constant ENUM (line 36) | ENUM = Tag(10)
constant UTF8String (line 37) | UTF8String = Tag(12)
constant SEQUENCE (line 38) | SEQUENCE = Tag(16 | classConstructed)
constant SET (line 39) | SET = Tag(17 | classConstructed)
constant PrintableString (line 40) | PrintableString = Tag(19)
constant T61String (line 41) | T61String = Tag(20)
constant IA5String (line 42) | IA5String = Tag(22)
constant UTCTime (line 43) | UTCTime = Tag(23)
constant GeneralizedTime (line 44) | GeneralizedTime = Tag(24)
constant GeneralString (line 45) | GeneralString = Tag(27)
FILE: cryptobyte/builder.go
type Builder (line 23) | type Builder struct
method Bytes (line 55) | func (b *Builder) Bytes() ([]byte, error) {
method BytesOrPanic (line 64) | func (b *Builder) BytesOrPanic() []byte {
method AddUint8 (line 72) | func (b *Builder) AddUint8(v uint8) {
method AddUint16 (line 77) | func (b *Builder) AddUint16(v uint16) {
method AddUint24 (line 83) | func (b *Builder) AddUint24(v uint32) {
method AddUint32 (line 88) | func (b *Builder) AddUint32(v uint32) {
method AddBytes (line 93) | func (b *Builder) AddBytes(v []byte) {
method AddUint8LengthPrefixed (line 129) | func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
method AddUint16LengthPrefixed (line 134) | func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
method AddUint24LengthPrefixed (line 139) | func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
method AddUint32LengthPrefixed (line 144) | func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) {
method callContinuation (line 148) | func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) {
method addLengthPrefixed (line 171) | func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f Builder...
method flushChild (line 200) | func (b *Builder) flushChild() {
method add (line 276) | func (b *Builder) add(bytes ...byte) {
method AddValue (line 304) | func (b *Builder) AddValue(v MarshalingValue) {
function NewBuilder (line 37) | func NewBuilder(buffer []byte) *Builder {
function NewFixedBuilder (line 46) | func NewFixedBuilder(buffer []byte) *Builder {
type BuilderContinuation (line 119) | type BuilderContinuation
type BuildError (line 124) | type BuildError struct
type MarshalingValue (line 294) | type MarshalingValue interface
FILE: cryptobyte/string.go
type String (line 22) | type String
method read (line 26) | func (s *String) read(n int) []byte {
method Skip (line 36) | func (s *String) Skip(n int) bool {
method ReadUint8 (line 42) | func (s *String) ReadUint8(out *uint8) bool {
method ReadUint16 (line 53) | func (s *String) ReadUint16(out *uint16) bool {
method ReadUint24 (line 64) | func (s *String) ReadUint24(out *uint32) bool {
method ReadUint32 (line 75) | func (s *String) ReadUint32(out *uint32) bool {
method readUnsigned (line 84) | func (s *String) readUnsigned(out *uint32, length int) bool {
method readLengthPrefixed (line 98) | func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool {
method ReadUint8LengthPrefixed (line 124) | func (s *String) ReadUint8LengthPrefixed(out *String) bool {
method ReadUint16LengthPrefixed (line 131) | func (s *String) ReadUint16LengthPrefixed(out *String) bool {
method ReadUint24LengthPrefixed (line 138) | func (s *String) ReadUint24LengthPrefixed(out *String) bool {
method ReadBytes (line 144) | func (s *String) ReadBytes(out *[]byte, n int) bool {
method CopyBytes (line 155) | func (s *String) CopyBytes(out []byte) bool {
method Empty (line 165) | func (s String) Empty() bool {
FILE: sm2/cert/gmx509.go
constant nameTypeEmail (line 48) | nameTypeEmail = 1
constant nameTypeDNS (line 49) | nameTypeDNS = 2
constant nameTypeURI (line 50) | nameTypeURI = 6
constant nameTypeIP (line 51) | nameTypeIP = 7
type publicKeyInfo (line 54) | type publicKeyInfo struct
type tbsCertificateRequest (line 60) | type tbsCertificateRequest struct
type certificateRequest (line 68) | type certificateRequest struct
function CreateCertificateRequest (line 75) | func CreateCertificateRequest(template *x509.CertificateRequest, pub *sm...
function marshalSANs (line 210) | func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP...
function oidInExtensions (line 234) | func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extens...
function marshalPublicKey (line 243) | func marshalPublicKey(pub *sm2.PublicKey) (publicKeyBytes []byte, public...
function newRawAttributes (line 257) | func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn...
function ParseCertificateRequest (line 275) | func ParseCertificateRequest(asn1Data []byte) (*x509.CertificateRequest,...
function parseCertificateRequest (line 288) | func parseCertificateRequest(in *certificateRequest) (*x509.CertificateR...
function parsePublicKey (line 342) | func parsePublicKey(keyData *publicKeyInfo) (interface{}, error) {
function parseRawAttributes (line 370) | func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeT...
function parseCSRExtensions (line 386) | func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension...
function forEachSAN (line 416) | func forEachSAN(extension []byte, callback func(tag int, data []byte) er...
function domainToReverseLabels (line 462) | func domainToReverseLabels(domain string) (reverseLabels []string, ok bo...
function parseSANExtension (line 495) | func parseSANExtension(value []byte) (dnsNames, emailAddresses []string,...
function VerifyDERCSRSign (line 528) | func VerifyDERCSRSign(asn1Data []byte, userId []byte) (bool, error) {
function VerifyCSRSign (line 536) | func VerifyCSRSign(csr *x509.CertificateRequest, userId []byte) bool {
function FillCertificateTemplateByCSR (line 541) | func FillCertificateTemplateByCSR(template *x509.Certificate, csr *x509....
function subjectBytes (line 553) | func subjectBytes(cert *x509.Certificate) ([]byte, error) {
function reverseBitsInAByte (line 561) | func reverseBitsInAByte(in byte) byte {
function asn1BitLength (line 571) | func asn1BitLength(bitString []byte) int {
function oidFromExtKeyUsage (line 638) | func oidFromExtKeyUsage(eku x509.ExtKeyUsage) (oid asn1.ObjectIdentifier...
type basicConstraints (line 647) | type basicConstraints struct
type authKeyId (line 653) | type authKeyId struct
type authorityInfoAccess (line 658) | type authorityInfoAccess struct
type policyInformation (line 664) | type policyInformation struct
type distributionPointName (line 669) | type distributionPointName struct
type distributionPoint (line 675) | type distributionPoint struct
function isIA5String (line 681) | func isIA5String(s string) error {
function buildExtensions (line 691) | func buildExtensions(template *x509.Certificate, subjectIsEmpty bool, au...
type validity (line 952) | type validity struct
type certificate (line 956) | type certificate struct
type tbsCertificate (line 963) | type tbsCertificate struct
type TBSCertificate (line 977) | type TBSCertificate
function CreateCertificateInfo (line 985) | func CreateCertificateInfo(template, parent *x509.Certificate, csr *x509...
function IssueCertificateBySoftCAKey (line 1038) | func IssueCertificateBySoftCAKey(cinfo *TBSCertificate, caPri *sm2.Priva...
function CreateCertificate (line 1046) | func CreateCertificate(cinfo *TBSCertificate, signature []byte) ([]byte,...
function ParseCertificate (line 1058) | func ParseCertificate(asn1Data []byte) (*x509.Certificate, error) {
function parseCertificate (line 1071) | func parseCertificate(in *certificate) (*x509.Certificate, error) {
function parseNameConstraintsExtension (line 1299) | func parseNameConstraintsExtension(out *x509.Certificate, e pkix.Extensi...
function isValidIPMask (line 1460) | func isValidIPMask(mask []byte) bool {
type rfc2821Mailbox (line 1487) | type rfc2821Mailbox struct
function parseRFC2821Mailbox (line 1496) | func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
function extKeyUsageFromOID (line 1633) | func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku x509.ExtKeyUsage...
FILE: sm2/cert/gmx509_test.go
function TestX500Name (line 18) | func TestX500Name(t *testing.T) {
function TestCreateCertificateRequest (line 29) | func TestCreateCertificateRequest(t *testing.T) {
function TestCreateCertificate (line 81) | func TestCreateCertificate(t *testing.T) {
FILE: sm2/keyexchange.go
type ExchangeResult (line 13) | type ExchangeResult struct
function reduce (line 19) | func reduce(x *big.Int, w int) *big.Int {
function calculateU (line 28) | func calculateU(w int, selfStaticPriv *PrivateKey, selfEphemeralPriv *Pr...
function kdfForExch (line 45) | func kdfForExch(digest hash.Hash, ux, uy *big.Int, za, zb []byte, keyBit...
function calculateInnerHash (line 77) | func calculateInnerHash(digest hash.Hash, ux *big.Int, za, zb []byte, p1...
function s1 (line 89) | func s1(digest hash.Hash, uy *big.Int, innerHash []byte) []byte {
function s2 (line 97) | func s2(digest hash.Hash, uy *big.Int, innerHash []byte) []byte {
function CalculateKeyWithConfirmation (line 105) | func CalculateKeyWithConfirmation(initiator bool, keyBits int, confirmat...
function ResponderConfirm (line 146) | func ResponderConfirm(responderS2 []byte, initiatorS2 []byte) bool {
FILE: sm2/keyexchange_test.go
constant KeyBits (line 9) | KeyBits = 128
function TestSM2KeyExchange (line 17) | func TestSM2KeyExchange(t *testing.T) {
FILE: sm2/sm2.go
constant BitSize (line 20) | BitSize = 256
constant KeyBytes (line 21) | KeyBytes = (BitSize + 7) / 8
constant UnCompress (line 22) | UnCompress = 0x04
type Sm2CipherTextType (line 25) | type Sm2CipherTextType
constant C1C2C3 (line 29) | C1C2C3 Sm2CipherTextType = 1
constant C1C3C2 (line 31) | C1C3C2 Sm2CipherTextType = 2
type P256V1Curve (line 43) | type P256V1Curve struct
type PublicKey (line 48) | type PublicKey struct
method GetUnCompressBytes (line 135) | func (pub *PublicKey) GetUnCompressBytes() []byte {
method GetRawBytes (line 161) | func (pub *PublicKey) GetRawBytes() []byte {
type PrivateKey (line 53) | type PrivateKey struct
method GetRawBytes (line 166) | func (pri *PrivateKey) GetRawBytes() []byte {
type sm2Signature (line 58) | type sm2Signature struct
type sm2CipherC1C3C2 (line 62) | type sm2CipherC1C3C2 struct
type sm2CipherC1C2C3 (line 68) | type sm2CipherC1C2C3 struct
function init (line 74) | func init() {
function initSm2P256V1 (line 78) | func initSm2P256V1() {
function GetSm2P256V1 (line 95) | func GetSm2P256V1() P256V1Curve {
function GenerateKey (line 99) | func GenerateKey(rand io.Reader) (*PrivateKey, *PublicKey, error) {
function RawBytesToPublicKey (line 114) | func RawBytesToPublicKey(bytes []byte) (*PublicKey, error) {
function RawBytesToPrivateKey (line 125) | func RawBytesToPrivateKey(bytes []byte) (*PrivateKey, error) {
function CalculatePubKey (line 182) | func CalculatePubKey(priv *PrivateKey) *PublicKey {
function nextK (line 189) | func nextK(rnd io.Reader, max *big.Int) (*big.Int, error) {
function xor (line 204) | func xor(data []byte, kdfOut []byte, dRemaining int) {
function bigIntTo32Bytes (line 211) | func bigIntTo32Bytes(bn *big.Int) []byte {
function kdf (line 221) | func kdf(digest hash.Hash, c1x *big.Int, c1y *big.Int, encData []byte) {
function notEncrypted (line 252) | func notEncrypted(encData []byte, in []byte) bool {
function Encrypt (line 262) | func Encrypt(pub *PublicKey, in []byte, cipherTextType Sm2CipherTextType...
function Decrypt (line 308) | func Decrypt(priv *PrivateKey, in []byte, cipherTextType Sm2CipherTextTy...
function MarshalCipher (line 348) | func MarshalCipher(in []byte, cipherTextType Sm2CipherTextType) ([]byte,...
function UnmarshalCipher (line 387) | func UnmarshalCipher(in []byte, cipherTextType Sm2CipherTextType) (out [...
function getZ (line 441) | func getZ(digest hash.Hash, curve *P256V1Curve, pubX *big.Int, pubY *big...
function calculateE (line 461) | func calculateE(digest hash.Hash, curve *P256V1Curve, pubX *big.Int, pub...
function MarshalSign (line 471) | func MarshalSign(r, s *big.Int) ([]byte, error) {
function UnmarshalSign (line 479) | func UnmarshalSign(sign []byte) (r, s *big.Int, err error) {
function SignToRS (line 488) | func SignToRS(priv *PrivateKey, userId []byte, in []byte) (r, s *big.Int...
function Sign (line 534) | func Sign(priv *PrivateKey, userId []byte, in []byte) ([]byte, error) {
function VerifyByRS (line 543) | func VerifyByRS(pub *PublicKey, userId []byte, src []byte, r, s *big.Int...
function Verify (line 578) | func Verify(pub *PublicKey, userId []byte, src []byte, sign []byte) bool {
FILE: sm2/sm2_loop_test.go
constant loopCount (line 11) | loopCount = 10
function TestSignVerifyLoop (line 22) | func TestSignVerifyLoop(t *testing.T) {
function TestSignVerifyLoop2 (line 53) | func TestSignVerifyLoop2(t *testing.T) {
function TestSignVerifyLoop3 (line 78) | func TestSignVerifyLoop3(t *testing.T) {
FILE: sm2/sm2_test.go
function TestGetSm2P256V1 (line 12) | func TestGetSm2P256V1(t *testing.T) {
function TestGenerateKey (line 21) | func TestGenerateKey(t *testing.T) {
function TestEncryptDecrypt_C1C2C3 (line 39) | func TestEncryptDecrypt_C1C2C3(t *testing.T) {
function TestEncryptDecrypt_C1C3C2 (line 71) | func TestEncryptDecrypt_C1C3C2(t *testing.T) {
function TestCipherDerEncode_C1C2C3 (line 103) | func TestCipherDerEncode_C1C2C3(t *testing.T) {
function TestCipherDerEncode_C1C3C2 (line 148) | func TestCipherDerEncode_C1C3C2(t *testing.T) {
type testSm2SignData (line 193) | type testSm2SignData struct
function TestSign (line 211) | func TestSign(t *testing.T) {
function TestVerify (line 239) | func TestVerify(t *testing.T) {
FILE: sm3/sm3.go
constant DigestLength (line 11) | DigestLength = 32
constant BlockSize (line 12) | BlockSize = 16
type sm3Digest (line 25) | type sm3Digest struct
method Sum (line 41) | func (digest *sm3Digest) Sum(b []byte) []byte {
method Size (line 48) | func (digest *sm3Digest) Size() int {
method BlockSize (line 56) | func (digest *sm3Digest) BlockSize() int {
method Reset (line 60) | func (digest *sm3Digest) Reset() {
method Write (line 88) | func (digest *sm3Digest) Write(p []byte) (n int, err error) {
method finish (line 123) | func (digest *sm3Digest) finish() {
method checkSum (line 137) | func (digest *sm3Digest) checkSum() [DigestLength]byte {
method processBlock (line 147) | func (digest *sm3Digest) processBlock() {
method processWord (line 218) | func (digest *sm3Digest) processWord(in []byte, inOff int32) {
method processLength (line 229) | func (digest *sm3Digest) processLength(bitLength int64) {
function New (line 35) | func New() hash.Hash {
function p0 (line 247) | func p0(x uint32) uint32 {
function p1 (line 253) | func p1(x uint32) uint32 {
function ff0 (line 259) | func ff0(x uint32, y uint32, z uint32) uint32 {
function ff1 (line 263) | func ff1(x uint32, y uint32, z uint32) uint32 {
function gg0 (line 267) | func gg0(x uint32, y uint32, z uint32) uint32 {
function gg1 (line 271) | func gg1(x uint32, y uint32, z uint32) uint32 {
function Sum (line 275) | func Sum(data []byte) [DigestLength]byte {
function PrintT (line 282) | func PrintT() {
FILE: sm3/sm3_test.go
function TestPrintT (line 14) | func TestPrintT(t *testing.T) {
function TestSum (line 18) | func TestSum(t *testing.T) {
function TestSm3Digest_Sum (line 24) | func TestSm3Digest_Sum(t *testing.T) {
function testSum (line 30) | func testSum(t *testing.T, src string, expected string) {
function testSm3DigestSum (line 39) | func testSm3DigestSum(t *testing.T, src string, expected string) {
function TestSm3Digest_Write (line 50) | func TestSm3Digest_Write(t *testing.T) {
FILE: sm4/sm4.go
constant BlockSize (line 12) | BlockSize = 16
constant KeySize (line 13) | KeySize = 16
type KeySizeError (line 66) | type KeySizeError
method Error (line 68) | func (k KeySizeError) Error() string {
type sm4Cipher (line 72) | type sm4Cipher struct
method BlockSize (line 88) | func (c *sm4Cipher) BlockSize() int {
method Encrypt (line 92) | func (c *sm4Cipher) Encrypt(dst, src []byte) {
method Decrypt (line 102) | func (c *sm4Cipher) Decrypt(dst, src []byte) {
function NewCipher (line 77) | func NewCipher(key []byte) (cipher.Block, error) {
function expandKey (line 112) | func expandKey(key []byte, forEnc bool) []uint32 {
function tau (line 138) | func tau(a uint32) uint32 {
function lAp (line 149) | func lAp(b uint32) uint32 {
function tAp (line 153) | func tAp(z uint32) uint32 {
function encRound (line 157) | func encRound(x0 uint32, x1 uint32, x2 uint32, x3 uint32, x4 uint32, rk ...
function decRound (line 163) | func decRound(x0 uint32, x1 uint32, x2 uint32, x3 uint32, x4 uint32, rk ...
function processBlock (line 169) | func processBlock(rk []uint32, in []byte, out []byte) {
function l (line 190) | func l(b uint32) uint32 {
function t (line 195) | func t(z uint32) uint32 {
function r (line 199) | func r(a []uint32) {
function f0 (line 208) | func f0(x []uint32, rk uint32) uint32 {
function f1 (line 212) | func f1(x []uint32, rk uint32) uint32 {
function f2 (line 216) | func f2(x []uint32, rk uint32) uint32 {
function f3 (line 220) | func f3(x []uint32, rk uint32) uint32 {
function ECBEncrypt (line 226) | func ECBEncrypt(key, plainText []byte) (cipherText []byte, err error) {
function ECBDecrypt (line 245) | func ECBDecrypt(key, cipherText []byte) (plainText []byte, err error) {
function CBCEncrypt (line 264) | func CBCEncrypt(key, iv, plainText []byte) (cipherText []byte, err error) {
function CBCDecrypt (line 282) | func CBCDecrypt(key, iv, cipherText []byte) (plainText []byte, err error) {
FILE: sm4/sm4_test.go
type sm4CbcTestData (line 11) | type sm4CbcTestData struct
function TestSm4_CBC_Encrypt (line 33) | func TestSm4_CBC_Encrypt(t *testing.T) {
type sm4EcbTestData (line 63) | type sm4EcbTestData struct
function TestSm4_ECB_Encrypt_PKCS5Padding (line 81) | func TestSm4_ECB_Encrypt_PKCS5Padding(t *testing.T) {
function TestSm4_ECB_Encrypt_ZeroPadding (line 105) | func TestSm4_ECB_Encrypt_ZeroPadding(t *testing.T) {
FILE: util/bigint.go
function Add (line 5) | func Add(x, y *big.Int) *big.Int {
function Sub (line 11) | func Sub(x, y *big.Int) *big.Int {
function Mod (line 17) | func Mod(x, y *big.Int) *big.Int {
function ModInverse (line 23) | func ModInverse(x, y *big.Int) *big.Int {
function Mul (line 29) | func Mul(x, y *big.Int) *big.Int {
function Lsh (line 35) | func Lsh(x *big.Int, n uint) *big.Int {
function SetBit (line 41) | func SetBit(x *big.Int, i int, b uint) *big.Int {
function And (line 47) | func And(x, y *big.Int) *big.Int {
FILE: util/bigint_test.go
function TestAdd (line 9) | func TestAdd(t *testing.T) {
function TestAdd2 (line 17) | func TestAdd2(t *testing.T) {
FILE: util/ec.go
function IsEcPointInfinity (line 5) | func IsEcPointInfinity(x, y *big.Int) bool {
function ZForAffine (line 12) | func ZForAffine(x, y *big.Int) *big.Int {
FILE: util/padding.go
function PKCS5Padding (line 5) | func PKCS5Padding(src []byte, blockSize int) []byte {
function PKCS5UnPadding (line 11) | func PKCS5UnPadding(src []byte) []byte {
function ZeroPadding (line 17) | func ZeroPadding(src []byte, blockSize int) []byte {
function UnZeroPadding (line 26) | func UnZeroPadding(src []byte, paddingLen int) []byte {
Condensed preview — 25 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (165K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 678,
"preview": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [u"
},
{
"path": ".gitignore",
"chars": 192,
"preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, build with `go test -c`\n*.test\n\n# Ou"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 5,
"preview": "# gm\n"
},
{
"path": "cryptobyte/README",
"chars": 74,
"preview": "这个包下的代码全部copy自SDK中的golang_org/x/crypto/cryptobyte包,这个包不对应用开放,所以只好全部copy过来\n"
},
{
"path": "cryptobyte/asn1/asn1.go",
"chars": 1547,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "cryptobyte/asn1.go",
"chars": 19279,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "cryptobyte/builder.go",
"chars": 8777,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "cryptobyte/string.go",
"chars": 4671,
"preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go.mod",
"chars": 40,
"preview": "module github.com/ZZMarquis/gm\n\ngo 1.12\n"
},
{
"path": "sm2/cert/gmx509.go",
"chars": 49961,
"preview": "package cert\n\nimport (\n\t\"bytes\"\n\t\"crypto/elliptic\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/asn1\"\n\t\"errors\"\n\t\"fmt\"\n"
},
{
"path": "sm2/cert/gmx509_test.go",
"chars": 3991,
"preview": "package cert\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/asn1\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t"
},
{
"path": "sm2/keyexchange.go",
"chars": 4386,
"preview": "package sm2\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"github.com/ZZMarquis/gm/sm3\"\n\t\"github.com/ZZMarquis/gm/uti"
},
{
"path": "sm2/keyexchange_test.go",
"chars": 1126,
"preview": "package sm2\n\nimport (\n\t\"crypto/rand\"\n\t\"testing\"\n)\n\nconst (\n\tKeyBits = 128\n)\n\nvar (\n\tinitiatorId = []byte(\"ABCDEFG1234\")\n"
},
{
"path": "sm2/sm2.go",
"chars": 14278,
"preview": "package sm2\n\nimport (\n\t\"bytes\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"encoding/asn1\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\""
},
{
"path": "sm2/sm2_loop_test.go",
"chars": 2337,
"preview": "package sm2\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"testing\"\n)\n\nconst loopCount = 10\n\nvar loopTest"
},
{
"path": "sm2/sm2_test.go",
"chars": 6284,
"preview": "package sm2\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"testing\"\n)\n\nfunc TestGetSm2P256V1(t *"
},
{
"path": "sm3/sm3.go",
"chars": 6317,
"preview": "package sm3\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"hash\"\n\t\"math/bits\"\n)\n\nconst (\n\tDigestLength = 32\n\tBlockSize = 16\n)\n"
},
{
"path": "sm3/sm3_test.go",
"chars": 1826,
"preview": "package sm3\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"testing\"\n)\n\nvar testData = map[string]string{\n\t\"abc\": \"66c7f0f46"
},
{
"path": "sm4/sm4.go",
"chars": 7811,
"preview": "package sm4\n\nimport (\n\t\"crypto/cipher\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"math/bits\"\n\t\"strconv\"\n)\n\nconst (\n\tBlockSize = 16\n\t"
},
{
"path": "sm4/sm4_test.go",
"chars": 3793,
"preview": "package sm4\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"github.com/ZZMarquis/gm/util\"\n\t\"testing\"\n)\n\ntype sm4CbcTestData "
},
{
"path": "util/bigint.go",
"chars": 688,
"preview": "package util\n\nimport \"math/big\"\n\nfunc Add(x, y *big.Int) *big.Int {\n\tvar z big.Int\n\tz.Add(x, y)\n\treturn &z\n}\n\nfunc Sub(x"
},
{
"path": "util/bigint_test.go",
"chars": 443,
"preview": "package util\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\t\"testing\"\n)\n\nfunc TestAdd(t *testing.T) {\n\ta := new(big.Int).SetInt64(1)\n\tb :"
},
{
"path": "util/ec.go",
"chars": 278,
"preview": "package util\n\nimport \"math/big\"\n\nfunc IsEcPointInfinity(x, y *big.Int) bool {\n\tif x.Sign() == 0 && y.Sign() == 0 {\n\t\tret"
},
{
"path": "util/padding.go",
"chars": 752,
"preview": "package util\n\nimport \"bytes\"\n\nfunc PKCS5Padding(src []byte, blockSize int) []byte {\n\tpadding := blockSize - len(src)%blo"
}
]
About this extraction
This page contains the full source code of the ZZMarquis/gm GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 25 files (147.4 KB), approximately 49.1k tokens, and a symbol index with 292 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.