tntengine

package module
v1.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 5, 2024 License: Unlicense Imports: 10 Imported by: 2

README

tntengine

tntengine is a golang implementation of a Z-80 assembler program described in an article in Dr. Dobbs Journal Volume 9, Number 94, 1984 titled An Infinite Key Encryption System by John A. Thomas and Joan Thersites. I will not be detailing the reasoning behind the design of the system, but instead refer you to the article for those detail. I will be describing the design of this golang implementation and what is different from the original code.

The first change is that program is broken out into two pieces:

  • tntengine, a module that only contains the code necessary to support the rotors and permutator that encrypts/decrypts the plaintext. it contains the code to initialize the rotors and permutators based on a supplied secret key. This module is essentially a pseudo-random number generator with a very long period.
  • tnt, the code that obtains the secret key, the file that to be encrypted/decrypted, the starting block number, and saves the next starting block number after the encryption is done.

In the original program, the rotors and permutator (note that there is only one permutator that is used twice) are applied sequentially then the rotors are stepped and the permutator is cycled. The next change is that the golang implementation makes use of golang's built-in concurrency features to run the rotors and permutators concurrently, which means the rotors are applied and stepped individually along with two identical permutators (instead of one) that are applied and cycled individually. This simulates the original code where one permutator is used twice before it is cycled.

To support this, an interface called Cryptor wad defined:

type Cryptor interface {
	Update(*Rand)                   // function to update the Cryptor (rotor or permutator)
	SetIndex(*big.Int)              // setter for the index value
	Index() *big.Int                // getter for the index value
	ApplyF(CipherBlock) CipherBlock // encryption function
	ApplyG(CipherBlock) CipherBlock // decryption function
}

There are three types, Rotor, Permutator, and Counter that satisfies the Cryptor interface. The Rotor and Permutator types provides the rotors and permutators used to encrypt/decrypt the plaintext. Counter, is a type that just counts the number of 32-byte blocks that have been encrypted/decrypted.

The Rotor and Permutator objects are wrapped in a go function that reads a CipherBlock from the input channel, calls the Applyf or Applyg function depending on whether the file is being encrypted or decrypted, and then sends processed CipherBlock to the output channel. The wrapped Rotor and Permutator objects are then chained together by connecting the output channel of one wrapped object to the input channel of the following object. The input of the first object in the chain is feed the data to be encrypted/decrypted and the output of the last object is the encrypted/decrypted data. To initialize tntengine, the (hard-coded) proforma rotors and permutator are used to build the proforma machine using the sequence of Rotor 1, Rotor 2, Permutator, Rotor 3, Rotor 4, Permutator, Rotor 5, and Rotor 6

proforma Encryption Machine

Once the TntEngine.engine is set up with the proforma machine, an encryption machine is created by linking the rotors and permutators together by wrapping them in a go function that reads a CipherBlock from the input channel, calls the Applyf function then sends processed CipherBlock to the output channel. Now a random number generator is created so that we can update the rotors and permutator with new (pseudo-)random data in a very non-linear manner. The rotors are updated CipherBlockBytes (32) bytes at a time to add additional complexity since the rotors are being modified as they are bing used.

Once the permutator and rotors have been updated, a new TntEngine.engine is created using the rotors in a random order and the rotors and permutator is used to create a new encryption machine. In the diagram below, the random order is [Rotor 3, Rotor 5, Rotor 1, Rotor 6, Rotor 4, Rotor 2].

Updated Encryption Machine

To create a decryption machine, the rotors are taken in reveres order.

Updated Decryption Machine

Once the encryption/decryption machine is created, the data can be encrypted/decrypted by passing in the slice of 32 bytes at a time to the input channel and reading the encrypted/decrypted data as a slice of 32 bytes from the output channel. In the original Z80 program, all the rotors and the permutator is applied to the 32 bytes of data before the next 32 bytes are processed. In the golang version, each rotor, permutator, and counter is applied to the 32 bytes of data as it is sent from one Cryptor to the next allowing nine (9) 32 byte blocks of data to be processed concurrently.

Documentation

Overview

This is free and unencumbered software released into the public domain. See the UNLICENSE file for details.

This is free and unencumbered software released into the public domain. See the UNLICENSE file for details.

Index

Constants

View Source
const (
	BitsPerByte      int = 8
	CipherBlockSize  int = 256 // bits
	CipherBlockBytes int = CipherBlockSize / BitsPerByte
)

Define constants needed for tntengine

View Source
const (
	EngineLayout = "rrprrprr" // 'r' is rotor, 'p' is permutator
)
View Source
const (
	NumberPermutationCycles int = 1
)

Variables

View Source
var (
	// BigZero - the big int value for zero.
	BigZero = big.NewInt(0)
	// BigOne - the big int value for one.
	BigOne = big.NewInt(1)
)

Functions

func ClrBit

func ClrBit(ary []byte, bit uint) []byte

ClrBit - clear bit in a byte array

func DecryptMachine

func DecryptMachine(ecm Cryptor, left chan CipherBlock) chan CipherBlock

DecryptMachine - set up a rotor, permutator, or counter to decrypt a block read from the left (input channel) and send it out on the right (output channel)

func EncryptMachine

func EncryptMachine(ecm Cryptor, left chan CipherBlock) chan CipherBlock

EncryptMachine - set up a rotor, permutator, or counter to encrypt a block read from the left (input channel) and send it out on the right (output channel)

func GetBit

func GetBit(ary []byte, bit uint) bool

GetBit - return the value of a bit in a byte array

func SetBit

func SetBit(ary []byte, bit uint) []byte

SetBit - set bit in a byte array

Types

type CipherBlock added in v1.5.0

type CipherBlock []byte

CipherBlock is the data processed by the cryptors (rotors and permutators). It consists of the length in bytes to process and the (32 bytes of) data to process.

func AddBlock

func AddBlock(blk, key CipherBlock) CipherBlock

AddBlock - adds (not XOR) the data to be encrypted with the key.

func SubBlock

func SubBlock(blk, key CipherBlock) CipherBlock

SubBlock - subtracts (not XOR) the key from the data to be decrypted

func (CipherBlock) String added in v1.5.0

func (cblk CipherBlock) String() string

String formats a string representing the CipherBlock.

type Counter

type Counter struct {
	// contains filtered or unexported fields
}

Counter is a Cryptor that does not encrypt/decrypt any data but counts the number of blocks that were encrypted.

func (*Counter) ApplyF

func (cntr *Counter) ApplyF(blk CipherBlock) CipherBlock

ApplyF - increments the counter for each block that is encrypted.

func (*Counter) ApplyG

func (cntr *Counter) ApplyG(blk CipherBlock) CipherBlock

ApplyG - this function does nothing for a Counter during decryption.

func (*Counter) Index

func (cntr *Counter) Index() *big.Int

Index - retrieves the current index value

func (*Counter) SetIndex

func (cntr *Counter) SetIndex(index *big.Int)

SetIndex - sets the initial index value

func (*Counter) String added in v1.5.0

func (cntr *Counter) String() string

String() - return the string representation (in base-10) of the Counter

func (*Counter) Update added in v1.4.0

func (cntr *Counter) Update(random *Rand)

type Cryptor added in v1.7.0

type Cryptor interface {
	Update(*Rand)                   // function to update the rotor/permutator
	SetIndex(*big.Int)              // setter for the index value
	Index() *big.Int                // getter for the index value
	ApplyF(CipherBlock) CipherBlock // encryption function
	ApplyG(CipherBlock) CipherBlock // decryption function
}

Cryptor interface

type Cycle

type Cycle struct {
	Start   int // The starting point (into randp) for this cycle.
	Length  int // The length of the cycle.
	Current int // The point in the cycle [0 .. cycle.length-1] to start
}

Cycle describes a cycle for the permutator so it can adjust the permutation table used to permute the block. TNT currently uses a single cycle to rearrange Randp into bitPerm

type Permutator

type Permutator struct {
	CurrentState  int    // Current number of cycles for this permutator.
	MaximalStates int    // Maximum number of cycles this permutator can have before repeating.
	Cycle         Cycle  // Cycles ordered by the current permutation.
	Randp         []byte // Values 0 - 255 in a random order.
	// contains filtered or unexported fields
}

Permutator is a type that defines a permutation crypter in TNT.

func (*Permutator) ApplyF

func (p *Permutator) ApplyF(blk CipherBlock) CipherBlock

ApplyF performs forward permutation on the 32 byte block of data. Note: if the length of the incoming block is less than CipherBlockBytes in length, then the permutation is not applied. This allows files whose length is not a multiple of 32 bytes to be correctly enrypted/decrypted.

func (*Permutator) ApplyG

func (p *Permutator) ApplyG(blk CipherBlock) CipherBlock

ApplyG performs the reverse permutation on the 32 byte block of data. Note: if the length of the incoming block is less than CipherBlockBytes in length, then the permutation is not applied. This allows files whose length is not a multiple of 32 bytes to be correctly enrypted/decrypted.

func (*Permutator) Index

func (p *Permutator) Index() *big.Int

Index returns the current index of the cryptor. For permeutators, this returns nil.

func (*Permutator) New added in v1.4.0

func (p *Permutator) New(cycleSize int, randp []byte) *Permutator

New creates a permutator and initializes it

func (*Permutator) SetIndex

func (p *Permutator) SetIndex(idx *big.Int)

SetIndex - set the Permutator to the state it would be in after encoding 'idx - 1' blocks of data.

func (*Permutator) String

func (p *Permutator) String() string

String formats a string representing the permutator (as Go source code).

func (*Permutator) Update

func (p *Permutator) Update(random *Rand)

Update will update the given (proForma) permutator in place using (psudo-)random data generated by the TNT encryption engine Rand object.

type Rand

type Rand struct {
	// contains filtered or unexported fields
}

func NewRand

func NewRand(src *TntEngine) *Rand

NewRand [deprecated] returns a Rand object.

func (*Rand) Int15n added in v1.6.0

func (rnd *Rand) Int15n(max int16) int16

Int15n returns, as an int16, a non-negative pseudo-random number in the half-open interval [0,n). It panics if n <= 0.

func (*Rand) Int31n added in v1.6.0

func (rnd *Rand) Int31n(max int32) int32

Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n). It panics if n <= 0.

func (*Rand) Int63n

func (rnd *Rand) Int63n(max int64) int64

Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n). It panics if n <= 0.

func (*Rand) Intn

func (rnd *Rand) Intn(max int) int

Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n) from the tntengine. It panics if n <= 0.

func (*Rand) New added in v1.4.0

func (rnd *Rand) New(src *TntEngine) *Rand

New returns a Rand object.

func (*Rand) Perm

func (rnd *Rand) Perm(n int) []int

func (*Rand) Read

func (rnd *Rand) Read(p []byte) (n int, err error)

type Rotor

type Rotor struct {
	Size    int    // the size in bits for this rotor
	Start   int    // the initial starting position of the rotor
	Step    int    // the step size in bits for this rotor
	Current int    // the current position of this rotor
	Rotor   []byte // the rotor
}

Rotor is the type of a TNT rotor

func (*Rotor) ApplyF

func (r *Rotor) ApplyF(blk CipherBlock) CipherBlock

ApplyF encrypts the given block of data using the rotor r.

func (*Rotor) ApplyG

func (r *Rotor) ApplyG(blk CipherBlock) CipherBlock

ApplyG decrypts the given block of data using the rotor r.

func (*Rotor) Index

func (r *Rotor) Index() *big.Int

Always return nil since the block count is not tracked for rotors.

func (*Rotor) New added in v1.4.0

func (r *Rotor) New(size, start, step int, rotor []byte) *Rotor

New fills the (empty) rotor r with the given size, start, step and rotor data.

func (*Rotor) SetIndex

func (r *Rotor) SetIndex(idx *big.Int)

SetIndex positions the rotor to the position it would be in after processing idx number of blocks.

func (*Rotor) String

func (r *Rotor) String() string

String converts a Rotor to a string representation of the Rotor.

func (*Rotor) Update

func (r *Rotor) Update(random *Rand)

Update rotor r with a new start, step and (pseudo-)random data.

type TntEngine

type TntEngine struct {
	// contains filtered or unexported fields
}

TntEngine type defines the encryption/decryption machine (rotors and permutators).

func (*TntEngine) BuildCipherMachine

func (e *TntEngine) BuildCipherMachine()

BuildCipherMachine will create a "machine" to encrypt or decrypt data sent to the left channel and outputted on the right channel for the TntEngine. The engineType determines wither a encrypt machine or a decrypt machine will be created.

func (*TntEngine) CloseCipherMachine added in v1.5.0

func (e *TntEngine) CloseCipherMachine()

CloseCipherMachine will close down the cipher machine by exiting the go function that performs the encryption/decryption using the individual rotors/permutators. This is done by passing the CipherMachine a CipherBlock with a length of zero (0).

func (*TntEngine) CounterKey

func (e *TntEngine) CounterKey() string

CounterKey is a getter that returns the SHAKE256 hash for the secret key. This is used to set/retrieve that next block to use in encrypting data from the file used to save the next block to use..

func (*TntEngine) Engine

func (e *TntEngine) Engine() []Cryptor

Engine is a getter function that returns a slice containing the rotors and permutators for the TntEngine.

func (*TntEngine) EngineType

func (e *TntEngine) EngineType() string

EngineType is a getter function that returns the engine type of the TntMachine.

func (*TntEngine) Index

func (e *TntEngine) Index() (cntr *big.Int)

Index is a getter that returns the block number of the next block to be encrypted.

func (*TntEngine) Init

func (e *TntEngine) Init(secret []byte)

Init will initialize the TntEngine generating new Rotors and Permutators using the proForma rotors and permutators in complex way, updating the rotors and permutators in place.

func (*TntEngine) Left

func (e *TntEngine) Left() chan CipherBlock

Left is a getter that returns the input channel for the TntEngine.

func (*TntEngine) MaximalStates added in v1.1.2

func (e *TntEngine) MaximalStates() *big.Int

MaximalStates is a getter function that returns maximum number of states that the engine can be in before repeating.

func (*TntEngine) Right

func (e *TntEngine) Right() chan CipherBlock

Right is a getter that returns the output channel for the TntEngine.

func (*TntEngine) SetEngineType

func (e *TntEngine) SetEngineType(engineType string)

SetEngineType is a setter function that sets the engineType [D)ecrypt or E)ncrypt] of the TntEngine.

func (*TntEngine) SetIndex

func (e *TntEngine) SetIndex(iCnt *big.Int)

SetIndex is a setter function that sets the rotors and permutators so that the TntEngine will be ready start encrypting/decrypting at the correct block.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL