Skip to content

Commit

Permalink
feat: 重构,bug修复,支持保持原大小写
Browse files Browse the repository at this point in the history
  • Loading branch information
CC11001100 committed Feb 15, 2024
1 parent be69840 commit b1a177e
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 39 deletions.
8 changes: 4 additions & 4 deletions examples/basic_usage/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@ package main

import (
"fmt"
qwerty_cipher "github.com/cryptography-research-lab/go-qwerty-cipher"
"github.com/cryptography-research-lab/go-qwerty-cipher/pkg/qwerty_cipher"
)

func main() {

// 对明文加密
plaintext := "helloworld"
plaintext := "HelloWorld"
encrypt, err := qwerty_cipher.Encrypt(plaintext)
if err != nil {
fmt.Println("加密时发生了错误: " + err.Error())
return
}
fmt.Println("加密结果: " + encrypt) // Output: 加密结果: ITSSGVGKSR
fmt.Println("加密结果: " + encrypt) // Output: 加密结果: ItssgVgksr

// 对密文解密
decrypt, err := qwerty_cipher.Decrypt(encrypt)
if err != nil {
fmt.Println("解密时发生了错误: " + err.Error())
return
}
fmt.Println("解密结果: " + decrypt) // Output: 解密结果: HELLOWORLD
fmt.Println("解密结果: " + decrypt) // Output: 解密结果: HelloWorld

}
14 changes: 7 additions & 7 deletions examples/custom_layout/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@ package main

import (
"fmt"
qwerty_cipher "github.com/cryptography-research-lab/go-qwerty-cipher"
qwerty_cipher2 "github.com/cryptography-research-lab/go-qwerty-cipher/pkg/qwerty_cipher"
)

func main() {

keywordLayout := qwerty_cipher.QwertzKeyboardLayout
keywordLayout := qwerty_cipher2.QwertzKeyboardLayout

// 对明文加密
plaintext := "helloworld"
encrypt, err := qwerty_cipher.Encrypt(plaintext, keywordLayout)
plaintext := "HelloWorld"
encrypt, err := qwerty_cipher2.Encrypt(plaintext, keywordLayout)
if err != nil {
fmt.Println("加密时发生了错误: " + err.Error())
return
}
fmt.Println("加密结果: " + encrypt) // Output: 加密结果: ITSSGVGKSR
fmt.Println("加密结果: " + encrypt) // Output: 加密结果: ItssgVgksr

// 对密文解密,解密的时候要将布局转换为解密使用的形式,如果是多次调用,则应该保存转换结果避免重复转换
decrypt, err := qwerty_cipher.Decrypt(encrypt, keywordLayout.TransformToDecrypt())
decrypt, err := qwerty_cipher2.Decrypt(encrypt, keywordLayout.TransformToDecrypt())
if err != nil {
fmt.Println("解密时发生了错误: " + err.Error())
return
}
fmt.Println("解密结果: " + decrypt) // Output: 解密结果: HELLOWORLD
fmt.Println("解密结果: " + decrypt) // Output: 解密结果: HelloWorld

}
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,18 @@ go 1.18

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/golang-infrastructure/go-StringBuilder v0.0.0-20221115030116-99376cd5eee4 // indirect
github.com/golang-infrastructure/go-variable-parameter v0.0.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/ivanpirog/coloredcobra v1.0.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/stretchr/testify v1.8.1 // indirect
golang.org/x/sys v0.17.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
34 changes: 34 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/golang-infrastructure/go-StringBuilder v0.0.0-20221115030116-99376cd5eee4 h1:9uTZOf+BQ7kvRm+cYt/KD0zoWIxtJUItHKU9C+aeJhU=
github.com/golang-infrastructure/go-StringBuilder v0.0.0-20221115030116-99376cd5eee4/go.mod h1:abDmAiNZRbUeZhhWMBM/TdC7RLvfazC/74zKsfiN9DU=
github.com/golang-infrastructure/go-variable-parameter v0.0.3 h1:+roJv+T/krkl5YMZtCXzdgDSP0RDWK0W1V2lTkpeDNA=
github.com/golang-infrastructure/go-variable-parameter v0.0.3/go.mod h1:qEnCqgG04+EpGWqRXaNpKhu4JsP6xcT85WpJyS83Dcw=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/ivanpirog/coloredcobra v1.0.1 h1:aURSdEmlR90/tSiWS0dMjdwOvCVUeYLfltLfbgNxrN4=
github.com/ivanpirog/coloredcobra v1.0.1/go.mod h1:iho4nEKcnwZFiniGSdcgdvRgZNjxm+h20acv8vqmN6Q=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
Expand All @@ -13,7 +39,15 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
4 changes: 3 additions & 1 deletion errors.go → pkg/qwerty_cipher/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ package qwerty_cipher

import "errors"

// ErrKeyboardLayoutCharacterInvalid 传入的键盘布局表中
// ErrKeyboardLayoutCharacterInvalid 传入的键盘布局表中指定的字母不合法,必须是A-Z每个字符都出现并且恰好出现一次
var ErrKeyboardLayoutCharacterInvalid = errors.New("all A-Z must appear in the keyboard layout table exactly once")


20 changes: 11 additions & 9 deletions layout.go → pkg/qwerty_cipher/layout.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package qwerty_cipher

// KeyboardLayout 表示一个键盘布局,这个布局可以是任意布局,只要是确定了映射关系就可以了
// 具体的例子详见 QwertyKeyboardLayout 实现
type KeyboardLayout []rune

// 检查当前的键盘布局映射表是否合法
Expand All @@ -11,12 +12,12 @@ func (x KeyboardLayout) check() error {
return ErrKeyboardLayoutCharacterInvalid
}

// 然后统计每个字符的出现次数
// 然后统计每个字符的出现次数,每个字符都必须出现,并且只能出现一次
characterCountSlice := make([]int, 26)
for _, character := range x {
character = toUppercaseIfNeed(character)
mappingToIndex := character - 'A'
if mappingToIndex >= 26 {
mappingToIndex := toMappingIndex(character)
// 给定的字符必须在有效范围
if mappingToIndex >= 26 || mappingToIndex < 0 {
return ErrKeyboardLayoutCharacterInvalid
}
characterCountSlice[mappingToIndex]++
Expand All @@ -33,10 +34,10 @@ func (x KeyboardLayout) check() error {
// TransformToDecrypt 将加密表转换为解密表
func (x KeyboardLayout) TransformToDecrypt() KeyboardLayout {
decryptTable := make([]rune, len(x))
for index, toCharacter := range x {
fromCharacter := rune('A' + index)
toIndex := toCharacter - 'A'
decryptTable[toIndex] = fromCharacter
for index, fromCharacter := range x {
toCharacter := rune('A' + index)
fromIndex := toMappingIndex(fromCharacter)
decryptTable[fromIndex] = toCharacter
}
return decryptTable
}
Expand Down Expand Up @@ -64,6 +65,7 @@ func init() {
// ------------------------------------------------ ---------------------------------------------------------------------

// QwertzKeyboardLayout qwertz布局键盘的加密映射表
// 维基百科: https://zh.wikipedia.org/zh-cn/QWERTZ%E9%8D%B5%E7%9B%A4
var QwertzKeyboardLayout KeyboardLayout

// QwertzKeyboardLayoutDecrypt qwertz布局键盘的解密映射表
Expand All @@ -83,7 +85,7 @@ func init() {

// ------------------------------------------------ ---------------------------------------------------------------------

// AzertyKeyboardLayout qwertz布局键盘的加密映射表
// AzertyKeyboardLayout Azerty布局键盘的加密映射表
var AzertyKeyboardLayout KeyboardLayout

// AzertyKeyboardLayoutDecrypt qwertz布局键盘的解密映射表
Expand Down
22 changes: 7 additions & 15 deletions qwerty.go → pkg/qwerty_cipher/qwerty.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package qwerty_cipher
import variable_parameter "github.com/golang-infrastructure/go-variable-parameter"

// Encrypt 对明文进行加密
// 支持指定自定义的键盘布局,如果不指定的话默认使用QWERTY
// 支持指定自定义的键盘布局,如果不指定的话默认使用QWERTY布局
func Encrypt(plaintext string, keyboardLayout ...KeyboardLayout) (string, error) {

// 未指定键盘布局时使用qwerty布局的键盘
Expand All @@ -16,14 +16,14 @@ func Encrypt(plaintext string, keyboardLayout ...KeyboardLayout) (string, error)

resultSlice := make([]rune, len(plaintext))
for index, character := range plaintext {
character = toUppercaseIfNeed(character)
// 非字母原样保存
if character < 'A' || character > 'Z' {
resultSlice[index] = character
} else {
if isLetter(character) {
// 字母的话做个映射
mappingTo := keyboardLayout[0][character-'A']
resultSlice[index] = mappingTo
mappingToIndex := toMappingIndex(character)
mappingToCharacter := followUppercaseOrLowercase(character, keyboardLayout[0][mappingToIndex])
resultSlice[index] = mappingToCharacter
} else {
resultSlice[index] = character
}
}

Expand All @@ -38,11 +38,3 @@ func Decrypt(ciphertext string, keyboardLayoutDecryptTable ...KeyboardLayout) (s

return Encrypt(ciphertext, keyboardLayoutDecryptTable...)
}

// 如果有必要的话则将其转为大写,否则原样返回
func toUppercaseIfNeed(character rune) rune {
if character >= 'a' && character <= 'z' {
character -= 32
}
return character
}
6 changes: 3 additions & 3 deletions qwerty_test.go → pkg/qwerty_cipher/qwerty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import (
)

func TestEncrypt(t *testing.T) {
plaintext := "helloworld"
plaintext := "HelloWorld"
encrypt, err := Encrypt(plaintext)
assert.Nil(t, err)
assert.Equal(t, "ITSSGVGKSR", encrypt)
assert.Equal(t, "ItssgVgksr", encrypt)

decrypt, err := Decrypt(encrypt)
assert.Nil(t, err)
assert.Equal(t, "HELLOWORLD", decrypt)
assert.Equal(t, plaintext, decrypt)
}
54 changes: 54 additions & 0 deletions pkg/qwerty_cipher/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package qwerty_cipher

// 判断给定的rune是否是英文字母
func isLetter(c rune) bool {
return isLowercaseLetter(c) || isUppercaseLetter(c)
}

// 判断是否是小写字母
func isLowercaseLetter(c rune) bool {
return c >= 'a' && c <= 'z'
}

// 判断是否是大写字母
func isUppercaseLetter(c rune) bool {
return c >= 'A' && c <= 'Z'
}

// 把字母转换为大写
func toUppercase(c rune) rune {
if isLowercaseLetter(c) {
c -= 32
}
return c
}

// 把字母转换为小写
func toLowercase(c rune) rune {
if isUppercaseLetter(c) {
c += 32
}
return c
}

// b跟随a的大小写特性
func followUppercaseOrLowercase(a, b rune) rune {
if isUppercaseLetter(a) {
b = toUppercase(b)
} else if isLowercaseLetter(a) {
b = toLowercase(b)
}
return b
}

// 把字符转换为键盘布局切片对应的下标,比如a和A转换为0,b和B转换为1,以此类推
func toMappingIndex(c rune) int {
if isLowercaseLetter(c) {
return int(c - 'a')
} else if isUppercaseLetter(c) {
return int(c - 'A')
} else {
return -1
}
}

0 comments on commit b1a177e

Please sign in to comment.