diff --git a/go.mod b/go.mod index b9baa3327..92545201d 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/urfave/cli v1.22.15 github.com/xtaci/kcp-go/v5 v5.6.8 - github.com/xtaci/qpp v1.1.6 + github.com/xtaci/qpp v1.1.7 github.com/xtaci/smux v1.5.24 github.com/xtaci/tcpraw v1.2.25 golang.org/x/crypto v0.25.0 diff --git a/go.sum b/go.sum index 558e43ab2..97dbfcc11 100644 --- a/go.sum +++ b/go.sum @@ -87,6 +87,8 @@ github.com/xtaci/qpp v1.1.5 h1:EpFDE3lpCkOtGVIQTxww0tjQEOOCohuBuISL+c7/iWw= github.com/xtaci/qpp v1.1.5/go.mod h1:dJS3usaXNMbWxZSWCAdxz01UgJcz9wXDkd4BccDY/V0= github.com/xtaci/qpp v1.1.6 h1:c0eVP1bbHQ+mDpPhT1FtKhKDGhikJGDw+tC/aVh9/pw= github.com/xtaci/qpp v1.1.6/go.mod h1:dJS3usaXNMbWxZSWCAdxz01UgJcz9wXDkd4BccDY/V0= +github.com/xtaci/qpp v1.1.7 h1:KmqJRsXz84EnWfsI+hoPMNhJsbI4M717wFijEwI/q6w= +github.com/xtaci/qpp v1.1.7/go.mod h1:dJS3usaXNMbWxZSWCAdxz01UgJcz9wXDkd4BccDY/V0= github.com/xtaci/smux v1.5.24 h1:77emW9dtnOxxOQ5ltR+8BbsX1kzcOxQ5gB+aaV9hXOY= github.com/xtaci/smux v1.5.24/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY= github.com/xtaci/tcpraw v1.2.25 h1:VDlqo0op17JeXBM6e2G9ocCNLOJcw9mZbobMbJjo0vk= diff --git a/vendor/github.com/xtaci/qpp/README.md b/vendor/github.com/xtaci/qpp/README.md index 2df7cacaa..3f64ba27d 100644 --- a/vendor/github.com/xtaci/qpp/README.md +++ b/vendor/github.com/xtaci/qpp/README.md @@ -1,4 +1,12 @@ # Quantum Permutation Pad +![image](https://github.com/xtaci/qpp/assets/2346725/7a05cc4b-b207-437e-a015-57918906b738) + +[![GoDoc][1]][2] [![Go Report Card][3]][4] + +[1]: https://godoc.org/github.com/xtaci/qpp?status.svg +[2]: https://pkg.go.dev/github.com/xtaci/qpp +[3]: https://goreportcard.com/badge/github.com/xtaci/qpp +[4]: https://goreportcard.com/report/github.com/xtaci/qpp The [Quantum Permutation Pad](https://link.springer.com/content/pdf/10.1140/epjqt/s40507-023-00164-3.pdf) (QPP) is a cryptographic protocol designed to leverage the principles of quantum mechanics for secure communication. While the exact details of the QPP can vary based on the specific implementation and the theoretical model, the general concept involves using quantum properties such as superposition and entanglement to enhance the security of data transmission. Here’s an overview of the QPP and its relationship to quantum mechanics and cryptography: diff --git a/vendor/github.com/xtaci/qpp/prng.go b/vendor/github.com/xtaci/qpp/prng.go new file mode 100644 index 000000000..3633cbb2d --- /dev/null +++ b/vendor/github.com/xtaci/qpp/prng.go @@ -0,0 +1,27 @@ +package qpp + +// xorshift64star is a pseudo-random number generator that is part of the xorshift family of PRNGs. +func xorshift64star(state uint64) uint64 { + state ^= state >> 12 + state ^= state << 25 + state ^= state >> 27 + return state * 2685821657736338717 +} + +// xorshift32 +func xorshift32(state uint32) uint32 { + state ^= state << 13 + state ^= state >> 17 + state ^= state << 5 + return state +} + +// xorshift16 +// +//go:inline +func xorshift16(state uint16) uint16 { + state ^= state << 7 + state ^= state >> 9 + state ^= state << 8 + return state +} diff --git a/vendor/github.com/xtaci/qpp/qpp.go b/vendor/github.com/xtaci/qpp/qpp.go index 12aca06f0..5c45e5fdc 100644 --- a/vendor/github.com/xtaci/qpp/qpp.go +++ b/vendor/github.com/xtaci/qpp/qpp.go @@ -2,13 +2,13 @@ package qpp import ( "crypto/aes" + "crypto/cipher" "crypto/hmac" "crypto/sha1" "crypto/sha256" "encoding/binary" "fmt" "math/big" - "math/rand" "unsafe" "golang.org/x/crypto/pbkdf2" @@ -24,8 +24,16 @@ const ( PBKDF2_LOOPS = 128 // Number of iterations for PBKDF2 CHUNK_DERIVE_SALT = "___QUANTUM_PERMUTATION_PAD_SEED_DERIVE___" CHUNK_DERIVE_LOOPS = 1024 + MAGIC = 0x1A2B3C4D5E6F7890 + PAD_SWITCH = 8 // switch pad for every PAD_SWITCH bytes ) +// Rand is a stateful random number generator +type Rand struct { + seed64 uint64 + count uint8 +} + // QuantumPermutationPad represents the encryption/decryption structure using quantum permutation pads // QPP is a cryptographic technique that leverages quantum-inspired permutation matrices to provide secure encryption. type QuantumPermutationPad struct { @@ -34,10 +42,10 @@ type QuantumPermutationPad struct { padsPtr uintptr // raw pointer to encryption pads rpadsPtr uintptr // raw pointer to encryption pads - numPads uint16 // Number of pads (permutation matrices) - qubits uint8 // Number of quantum bits, determines the size of each pad - encRand *rand.Rand // Default random source for encryption pad selection - decRand *rand.Rand // Default random source for decryption pad selection + numPads uint16 // Number of pads (permutation matrices) + qubits uint8 // Number of quantum bits, determines the size of each pad + encRand *Rand // Default random source for encryption pad selection + decRand *Rand // Default random source for decryption pad selection } // NewQPP creates a new Quantum Permutation Pad instance with the provided seed, number of pads, and qubits @@ -55,6 +63,14 @@ func NewQPP(seed []byte, numPads uint16, qubits uint8) *QuantumPermutationPad { qpp.rpadsPtr = uintptr(unsafe.Pointer(unsafe.SliceData(qpp.rpads))) chunks := seedToChunks(seed, qubits) + // creat AES-256 blocks to generate random number for shuffling + var blocks []cipher.Block + for i := range chunks { + aeskey := pbkdf2.Key(chunks[i], []byte(SHUFFLE_SALT), PBKDF2_LOOPS, 32, sha1.New) + block, _ := aes.NewCipher(aeskey) + blocks = append(blocks, block) + } + // Initialize and shuffle pads to create permutation matrices for i := 0; i < int(numPads); i++ { pad := qpp.pads[i*matrixBytes : (i+1)*matrixBytes] @@ -63,7 +79,7 @@ func NewQPP(seed []byte, numPads uint16, qubits uint8) *QuantumPermutationPad { // Fill pad with sequential byte values fill(pad) // Shuffle pad to create a unique permutation matrix - shuffle(chunks[i%len(chunks)], qubits, pad, uint16(i)) + shuffle(chunks[i%len(chunks)], qubits, pad, uint16(i), blocks) // Create the reverse permutation matrix for decryption reverse(pad, rpad) } @@ -88,42 +104,76 @@ func (qpp *QuantumPermutationPad) Decrypt(data []byte) { // CreatePRNG creates a deterministic pseudo-random number generator based on the provided seed // It uses HMAC and PBKDF2 to derive a random seed for the PRNG -func (qpp *QuantumPermutationPad) CreatePRNG(seed []byte) *rand.Rand { +func (qpp *QuantumPermutationPad) CreatePRNG(seed []byte) *Rand { mac := hmac.New(sha256.New, seed) mac.Write([]byte(PM_SELECTOR_IDENTIFIER)) sum := mac.Sum(nil) dk := pbkdf2.Key(sum, []byte(PRNG_SALT), PBKDF2_LOOPS, 8, sha1.New) // Derive a key for PRNG - source := rand.NewSource(int64(binary.LittleEndian.Uint64(dk))) // Create random source - return rand.New(source) // Create and return PRNG + seed64 := binary.LittleEndian.Uint64(dk) + if seed64 == 0 { + seed64 = MAGIC + } + return &Rand{seed64: seed64} // Create and return PRNG } // EncryptWithPRNG encrypts the data using the Quantum Permutation Pad with a custom PRNG // This function shares the same permutation matrices -func (qpp *QuantumPermutationPad) EncryptWithPRNG(data []byte, rand *rand.Rand) { +func (qpp *QuantumPermutationPad) EncryptWithPRNG(data []byte, rand *Rand) { + // initial r, index, count + r := uint32(rand.seed64) + index := uint16(r) % qpp.numPads // Select a permutation matrix index + count := rand.count + + // loop switch qpp.qubits { case NATIVE_BYTE_LENGTH: for i := 0; i < len(data); i++ { - r := uint16(rand.Uint32()) // Generate a pseudo-random number - index := r % qpp.numPads // Select a permutation matrix index + // switch to another permutation pad for every 256 bytes + if count%PAD_SWITCH == 0 { + index = uint16(r) % qpp.numPads + count = 0 + } + offset := qpp.padsPtr + uintptr(index)<<8 + uintptr(data[i]^byte(r)) // Calculate the offset data[i] = *(*byte)(unsafe.Pointer(offset)) // Apply the permutation to the data byte + + count++ + r = xorshift32(r) } + + // set back r & count + rand.seed64 = uint64(r) + rand.count += uint8(len(data) % PAD_SWITCH) default: // Handle other cases if needed } + } // DecryptWithPRNG decrypts the data using the Quantum Permutation Pad with a custom PRNG // This function shares the same permutation matrices -func (qpp *QuantumPermutationPad) DecryptWithPRNG(data []byte, rand *rand.Rand) { +func (qpp *QuantumPermutationPad) DecryptWithPRNG(data []byte, rand *Rand) { + r := uint32(rand.seed64) + index := uint16(r) % qpp.numPads // Select a permutation matrix index + count := rand.count + switch qpp.qubits { case NATIVE_BYTE_LENGTH: for i := 0; i < len(data); i++ { - r := uint16(rand.Uint32()) // Generate a pseudo-random number - index := r % qpp.numPads // Select a permutation matrix index + if count%PAD_SWITCH == 0 { + index = uint16(r) % qpp.numPads + count = 0 + } + offset := qpp.rpadsPtr + uintptr(index)<<8 + uintptr(data[i]) // Calculate the offset data[i] = *(*byte)(unsafe.Pointer(offset)) ^ byte(r) // Apply the permutation to the data byte + count++ + r = xorshift32(r) } + + // set back r & count + rand.seed64 = uint64(r) + rand.count += uint8(len(data) % PAD_SWITCH) default: // Handle other cases if needed } @@ -205,18 +255,21 @@ func seedToChunks(seed []byte, qubits uint8) [][]byte { // shuffle shuffles the pad based on the seed and pad identifier to create a permutation matrix // It uses HMAC and PBKDF2 to derive a unique shuffle pattern from the seed and pad ID -func shuffle(chunk []byte, qubits uint8, pad []byte, padID uint16) { +func shuffle(chunk []byte, qubits uint8, pad []byte, padID uint16, blocks []cipher.Block) { + // use selected chunk based on pad ID to hmac the PAD_IDENTIFIER message := fmt.Sprintf(PAD_IDENTIFIER, padID) mac := hmac.New(sha256.New, chunk) mac.Write([]byte(message)) sum := mac.Sum(nil) - // Expand the seed to 32 bytes for AES-based PRNG - aeskey := pbkdf2.Key(chunk, []byte(SHUFFLE_SALT), PBKDF2_LOOPS, 32, sha1.New) - block, _ := aes.NewCipher(aeskey) for i := len(pad) - 1; i > 0; i-- { - block.Encrypt(sum, sum) + // use all the entropy from the seed to generate a random number + for j := 0; j < len(blocks); j++ { + block := blocks[j%len(blocks)] + block.Encrypt(sum, sum) + } bigrand := new(big.Int).SetBytes(sum) + j := bigrand.Mod(bigrand, big.NewInt(int64(i+1))).Uint64() pad[i], pad[j] = pad[j], pad[i] } diff --git a/vendor/modules.txt b/vendor/modules.txt index 344115ec3..fd1d86fdc 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -38,7 +38,7 @@ github.com/urfave/cli # github.com/xtaci/kcp-go/v5 v5.6.8 ## explicit; go 1.21 github.com/xtaci/kcp-go/v5 -# github.com/xtaci/qpp v1.1.6 +# github.com/xtaci/qpp v1.1.7 ## explicit; go 1.22.3 github.com/xtaci/qpp # github.com/xtaci/smux v1.5.24