1. 程式人生 > >GO語言JAVA語言實現的AES/CFB/256位的加密解密例子

GO語言JAVA語言實現的AES/CFB/256位的加密解密例子

AES加密解密演算法裡面,最複雜的的就是CFB模式,因為CFB模式每次附加隨機一個IV,造成同樣的KEY,每次生成的加密串不一樣。解密的時候要用到這個IV,IV附加在了加密好的資料裡面,有的實現是把IV放資料的最後,有的是最面前,比如加密之後的資料是XXX,    則最終的資料是  16Bytes的IV+XXX或者是XXX+16Bytes的IV。

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"errors"
)

var pass = flag.String("pass", "Password111111111111111111111111", "32 char password phrase- can be set to anything but keep it private")
var text = flag.String("text", "HelloWorld", "plain text to encode")
var cipherText = flag.String("cipher", "", "cipher text")
var verbose = flag.Bool("verbose", false, "verbose flag")

func main() {
	flag.Parse()
	key := []byte(*pass) // 32 bytes
	if len(os.Args) < 2 {
		println("usage: goAES -pass Password111111111111111111111111 -text HelloWorld")
		println("or")
		println("usage: goAES -pass Password111111111111111111111111 -cipher HnOnMPZAb32fz1f80VIL2pjQ+ahp/upo")
		os.Exit(1)
	}
	data := "ILOVEYOUFOREVER"
	mystring := base64.StdEncoding.EncodeToString([]byte(data))
	fmt.Printf("BASE64 = %s\n", mystring)
	
	if *cipherText == "" {
		plaintext := []byte(*text)
		ciphertextOutput, err := Actia_encrypt(key, plaintext)
		if err != nil {
			log.Fatal(err)
		}
		ciphertextOutput1, err := MIKE_encrypt(key, plaintext)
		
		fmt.Printf("Actia  ENCRYTP = %s\n", ciphertextOutput)
		fmt.Printf("MIKE   ENCRYTP = %s\n", ciphertextOutput1)
	} else {
		cipherBytes, err := base64.StdEncoding.DecodeString(*cipherText)
		if err != nil {
			log.Fatal("ERR=", err)
		}
		println("start DDecrypt")
		result, err := Actia_decrypt(key, cipherBytes)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("ACTIA_DECRYPT=%s\n", result)
		
		result1, err := MIKE_decrypt(key, cipherBytes)
		fmt.Printf("MIKE_DECRYPT=%s\n", result1)
	}
}

func Actia_encrypt(key, text []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	//b := base64.StdEncoding.EncodeToString(text)
	b := text
	ciphertext := make([]byte, aes.BlockSize+len(b))
	if *verbose {
		println("blocksize=", aes.BlockSize, "ciphertext=", string(ciphertext))
	}
	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}
	cfb := cipher.NewCFBEncrypter(block, iv)
	cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
	
	return []byte(base64.StdEncoding.EncodeToString(ciphertext)), nil
	//return ciphertext, nil
}



func Actia_decrypt(key, text []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	iv := text[:aes.BlockSize]
	text = text[aes.BlockSize:]
	if *verbose {
		println("iv", base64.StdEncoding.EncodeToString(iv), "cipher text", base64.StdEncoding.EncodeToString(iv))
	}
	cfb := cipher.NewCFBDecrypter(block, []byte(iv))
	cfb.XORKeyStream(text, text)
	//data, err := base64.StdEncoding.DecodeString(string(text))
	//if err != nil {
	//	return nil, err
	//}
	//str := string(text[:])
    //fmt.Println(str)
	return text, nil
}

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

//Here is our encrypt:

func MIKE_encrypt(key, text []byte) ([]byte, error) {
                block, err := aes.NewCipher(key)
                if err != nil {
                                return nil, err
                }
                ciphertext := make([]byte, aes.BlockSize+len(text))
                iv := ciphertext[:aes.BlockSize]
                if _, err := io.ReadFull(rand.Reader, iv); err != nil {
                                return nil, err
                }
                cfb := cipher.NewCFBEncrypter(block, iv)
                cfb.XORKeyStream(ciphertext[aes.BlockSize:], text)
                return []byte(base64.StdEncoding.EncodeToString(ciphertext)), nil
}

//And this should be a working decrypt:

func MIKE_decrypt(key, text []byte) ([]byte, error) {
       block, err := aes.NewCipher(key)
       if err != nil {
              return nil, err
       }
       if len(text) < aes.BlockSize {
              return nil, errors.New("ciphertext too short")
       }
       iv := text[:aes.BlockSize]
       text = text[aes.BlockSize:]
       cfb := cipher.NewCFBDecrypter(block, iv)
       cfb.XORKeyStream(text, text)
       data, err := base64.StdEncoding.DecodeString(string(text))
       if err != nil {
              return nil, err
       }
       return data, nil
}


用golang加密好之後, 用java解密,JAVA解密的程式碼在我上傳的資源裡有,我上傳的資源裡我自己修改過程式碼。

JAVA原始碼在GitHub上的下載地址是:https://github.com/platinumjesus/crypto015,

需要下載和你jdk對應版本的 US_export_policy.jar和local_policy.jar 包, 替換你安裝目錄裡的這兩個包, 否則會有問題。

http://stackoverflow.com/questions/6481627/java-security-illegal-key-size-or-default-parameters

另外需要注意的就是  IV 的位置, 上面的go程式碼把IV放在前面, java程式碼放在了後面, 得修改了對應起來,否則go加密的資料java無法解密。

還有就是我用的祕鑰是256位的。

go語言直接是  32 個byte的字串, java需要把32個byte的字串轉化為16進位制的字串, 長度是64個bytes,程式碼會再把64個byte的字串轉化為32個byte的二進位制key,本質都是256位的祕鑰, 只不過方便人工檢視祕鑰而已。