mirror of
https://github.com/lukaszraczylo/go-obfuscation.git
synced 2026-10-12 05:32:33 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
package strenc
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
const buildSeed = 0xDEAD_BEEF_CAFE_BABE
|
||||
|
||||
func DeriveMasterKey(seed [32]byte) [32]byte {
|
||||
var out [32]byte
|
||||
|
||||
mac := hmac.New(sha256.New, seed[:])
|
||||
mac.Write([]byte("strenc.masterkey.v1"))
|
||||
copy(out[:16], mac.Sum(nil))
|
||||
|
||||
mac.Reset()
|
||||
mac.Write(seed[:])
|
||||
mac.Write([]byte("strenc.masterkey.v2"))
|
||||
copy(out[16:], mac.Sum(nil))
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func DeriveFromBinary() [32]byte {
|
||||
exePath, err := os.Executable()
|
||||
if err != nil {
|
||||
exePath = "unknown"
|
||||
}
|
||||
|
||||
mac := hmac.New(sha256.New, []byte("strenc.binary.seed"))
|
||||
mac.Write([]byte(exePath))
|
||||
|
||||
var seedBuf [8]byte
|
||||
binary.LittleEndian.PutUint64(seedBuf[:], buildSeed)
|
||||
mac.Write(seedBuf[:])
|
||||
|
||||
mac.Write([]byte(runtime.GOOS))
|
||||
mac.Write([]byte(runtime.GOARCH))
|
||||
|
||||
var seed [32]byte
|
||||
copy(seed[:], mac.Sum(nil))
|
||||
|
||||
return DeriveMasterKey(seed)
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package strenc
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Entry struct {
|
||||
Ciphertext []byte
|
||||
IV [16]byte
|
||||
}
|
||||
|
||||
type Pool struct {
|
||||
data []byte
|
||||
offsets []int
|
||||
lengths []int
|
||||
entries int
|
||||
masterKey [32]byte
|
||||
}
|
||||
|
||||
func NewPool(masterKeySeed [32]byte, entries []Entry) *Pool {
|
||||
p := &Pool{
|
||||
masterKey: DeriveMasterKey(masterKeySeed),
|
||||
}
|
||||
p.entries = len(entries)
|
||||
|
||||
totalSize := 0
|
||||
for _, e := range entries {
|
||||
totalSize += 16 + len(e.Ciphertext)
|
||||
}
|
||||
|
||||
p.data = make([]byte, 0, totalSize)
|
||||
p.offsets = make([]int, len(entries))
|
||||
p.lengths = make([]int, len(entries))
|
||||
|
||||
for i, e := range entries {
|
||||
p.offsets[i] = len(p.data)
|
||||
p.data = append(p.data, e.IV[:]...)
|
||||
p.data = append(p.data, e.Ciphertext...)
|
||||
p.lengths[i] = 16 + len(e.Ciphertext)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Pool) StringCount() int {
|
||||
return p.entries
|
||||
}
|
||||
|
||||
func (p *Pool) deriveSubkey(iv [16]byte) [32]byte {
|
||||
mac := hmac.New(sha256.New, p.masterKey[:])
|
||||
mac.Write(iv[:])
|
||||
var subkey [32]byte
|
||||
copy(subkey[:], mac.Sum(nil))
|
||||
return subkey
|
||||
}
|
||||
|
||||
func (p *Pool) decryptAt(index int) ([]byte, error) {
|
||||
if index < 0 || index >= p.entries {
|
||||
return nil, fmt.Errorf("strenc: index %d out of range [0, %d)", index, p.entries)
|
||||
}
|
||||
|
||||
start := p.offsets[index]
|
||||
raw := p.data[start : start+p.lengths[index]]
|
||||
|
||||
var iv [16]byte
|
||||
copy(iv[:], raw[:16])
|
||||
ct := raw[16:]
|
||||
|
||||
subkey := p.deriveSubkey(iv)
|
||||
block, err := aes.NewCipher(subkey[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("strenc: aes.NewCipher: %w", err)
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("strenc: cipher.NewGCM: %w", err)
|
||||
}
|
||||
|
||||
nonceSize := gcm.NonceSize()
|
||||
if len(ct) < nonceSize {
|
||||
return nil, fmt.Errorf("strenc: ciphertext too short")
|
||||
}
|
||||
|
||||
nonce := ct[:nonceSize]
|
||||
ciphertext := ct[nonceSize:]
|
||||
|
||||
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("strenc: gcm.Open: %w", err)
|
||||
}
|
||||
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
func (p *Pool) GetString(index int) string {
|
||||
pt, err := p.decryptAt(index)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(pt)
|
||||
}
|
||||
|
||||
func (p *Pool) GetStringZero(index int, fn func(string)) {
|
||||
pt, err := p.decryptAt(index)
|
||||
if err != nil {
|
||||
fn("")
|
||||
return
|
||||
}
|
||||
|
||||
buf := make([]byte, len(pt))
|
||||
copy(buf, pt)
|
||||
s := string(buf)
|
||||
|
||||
for i := range pt {
|
||||
pt[i] = 0
|
||||
}
|
||||
|
||||
fn(s)
|
||||
|
||||
for i := range buf {
|
||||
buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func EncryptEntry(plaintext string, key [32]byte, iv [16]byte) Entry {
|
||||
block, err := aes.NewCipher(key[:])
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("strenc: aes.NewCipher: %v", err))
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("strenc: cipher.NewGCM: %v", err))
|
||||
}
|
||||
|
||||
nonceSize := gcm.NonceSize()
|
||||
nonce := make([]byte, nonceSize)
|
||||
copy(nonce, iv[:nonceSize])
|
||||
|
||||
ct := gcm.Seal(nonce, nonce, []byte(plaintext), nil)
|
||||
|
||||
return Entry{
|
||||
Ciphertext: ct,
|
||||
IV: iv,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user