diff --git a/bridge/bridge.go b/bridge/bridge.go index a531807..17613ef 100644 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -3,7 +3,8 @@ package bridge import ( "fmt" - "crypto/cipher" + + "github.com/andlabs/reallymine/decryptloop" ) var ErrWrongKEK = fmt.Errorf("wrong KEK") @@ -16,7 +17,7 @@ type Bridge interface { // do not check if KEK is wrong; that will be done in KeySector.DEK() // this way, we can still use KeySector.Raw() for research and debugging DecryptKeySector(keySector []byte, kek []byte) (ks KeySector, err error) - Decrypt(c cipher.Block, b []byte) + DecryptLoopSteps() decryptloop.StepList } type KeySector interface { diff --git a/bridge/initio.go b/bridge/initio.go index b0976d8..32ffc40 100644 --- a/bridge/initio.go +++ b/bridge/initio.go @@ -3,11 +3,11 @@ package bridge import ( "bytes" - "crypto/cipher" "crypto/aes" "encoding/binary" "github.com/andlabs/reallymine/byteops" + "github.com/andlabs/reallymine/decryptloop" ) type Initio struct{} @@ -93,13 +93,12 @@ func (ks *InitioKeySector) DEK() (dek []byte, err error) { return dek, nil } -func (Initio) Decrypt(c cipher.Block, b []byte) { - for i := 0; i < len(b); i += 16 { - block := b[i : i+16] - byteops.SwapLongs(block) - c.Decrypt(block, block) +func (Initio) DecryptLoopSteps() decryptloop.StepList { + return decryptloop.StepList{ + decryptloop.StepSwapLongs, + decryptloop.StepDecrypt, // We DO need to swap again after this, though! - byteops.SwapLongs(block) + decryptloop.StepSwapLongs, } } diff --git a/bridge/jmicron.go b/bridge/jmicron.go index d1931c9..f8412b7 100644 --- a/bridge/jmicron.go +++ b/bridge/jmicron.go @@ -3,11 +3,11 @@ package bridge import ( "bytes" - "crypto/cipher" "crypto/aes" "encoding/binary" "github.com/andlabs/reallymine/byteops" + "github.com/andlabs/reallymine/decryptloop" ) type JMicron struct{} @@ -117,12 +117,11 @@ func (ks *JMicronKeySector) DEK() (dek []byte, err error) { return dek, nil } -func (JMicron) Decrypt(c cipher.Block, b []byte) { - for i := 0; i < len(b); i += 16 { - block := b[i : i+16] - byteops.Reverse(block) - c.Decrypt(block, block) - byteops.Reverse(block) +func (JMicron) DecryptLoopSteps() decryptloop.StepList { + return decryptloop.StepList{ + decryptloop.StepReverse, + decryptloop.StepDecrypt, + decryptloop.StepReverse, } } diff --git a/bridge/symwave.go b/bridge/symwave.go index 384121e..bd16506 100644 --- a/bridge/symwave.go +++ b/bridge/symwave.go @@ -2,11 +2,11 @@ package bridge import ( - "crypto/cipher" "bytes" "encoding/binary" "github.com/andlabs/reallymine/byteops" + "github.com/andlabs/reallymine/decryptloop" "github.com/mendsley/gojwe" ) @@ -101,11 +101,10 @@ func (ks *SymwaveKeySector) DEK() (dek []byte, err error) { return dek, nil } -func (Symwave) Decrypt(c cipher.Block, b []byte) { - for i := 0; i < len(b); i += 16 { - block := b[i : i+16] - // ...and we can just use block as-is! - c.Decrypt(block, block) +func (Symwave) DecryptLoopSteps() decryptloop.StepList { + return decryptloop.StepList{ + // ...and we can just decrypt the encrypted blocks as-is! + decryptloop.StepDecrypt, } } diff --git a/decrypter.go b/decrypter.go index 166c670..e204c2f 100644 --- a/decrypter.go +++ b/decrypter.go @@ -9,6 +9,7 @@ import ( "github.com/andlabs/reallymine/disk" "github.com/andlabs/reallymine/bridge" "github.com/andlabs/reallymine/kek" + "github.com/andlabs/reallymine/decryptloop" ) // TODO rename this type @@ -92,6 +93,8 @@ func (d *Decrypter) DecryptDisk() error { if err != nil { return err } + steps := d.Bridge.DecryptLoopSteps() + dl := decryptloop.New(steps, cipher, d.Out) // TODO refine or allow custom buffer sizes? iter, err := d.Disk.Iter(0, 1) if err != nil { @@ -99,8 +102,7 @@ func (d *Decrypter) DecryptDisk() error { } for iter.Next() { s := iter.Sectors() - d.Bridge.Decrypt(cipher, s) - _, err = d.Out.Write(s) + _, err = dl.Write(s) if err != nil { return err } diff --git a/decryptloop/decryptloop.go b/decryptloop/decryptloop.go index cfd78dc..ef3d6d5 100644 --- a/decryptloop/decryptloop.go +++ b/decryptloop/decryptloop.go @@ -2,14 +2,12 @@ package decryptloop import ( - "fmt" "io" - "strings" "crypto/cipher" ) type DecryptLoop struct { - steps []Step + steps StepList c cipher.Block buf []byte out io.Writer @@ -24,37 +22,16 @@ func New(steps []Step, c cipher.Block, out io.Writer) *DecryptLoop { } } -type UnknownStepNameError string - -func (e UnknownStepNameError) Error() string { - return fmt.Sprintf("unknown decrypt loop step name %q", string(e)) -} - func FromString(s string, c cipher.Block, out io.Writer) (*DecryptLoop, error) { - names := strings.Split(s, " ") - steps := make([]Step, len(names)) - for i, name := range names { - step, ok := stepsByName[name] - if !ok { - return nil, UnknownStepNameError(name) - } - steps[i] = step + steps, err := stepListFromString(s) + if err != nil { + return nil, err } return New(steps, c, out), nil } -func (dl *DecryptLoop) String() string { - names := make([]string, len(dl.steps)) - for i, step := range dl.steps { - names[i] = step.name() - } - return strings.Join(names, " ") -} - func (dl *DecryptLoop) writeBlock() (n int, err error) { - for _, step := range dl.steps { - step.do(dl.c, dl.buf) - } + dl.steps.runBlock(dl.c, dl.buf) n, err = dl.out.Write(dl.buf) dl.buf = dl.buf[0:0] // reuse dl.buf return n, err diff --git a/decryptloop/steps.go b/decryptloop/steps.go index 98e1e5d..1e31fb3 100644 --- a/decryptloop/steps.go +++ b/decryptloop/steps.go @@ -4,6 +4,7 @@ package decryptloop import ( "fmt" "crypto/cipher" + "strings" "github.com/andlabs/reallymine/byteops" ) @@ -30,7 +31,7 @@ var stepsByName = make(map[string]Step) func addstep(s stepiface) Step { ss := Step{s} validSteps = append(validSteps, ss) - stepsByName[ss.name()] = ss + stepsByName[ss.s.name()] = ss return ss } @@ -119,14 +120,41 @@ func (stepSwapHalvesType) do(c cipher.Block, b []byte) { var stepSwapHalves = addstep(&stepSwapHalvesType{}) var StepSwapHalves Step = stepSwapHalves +type StepList []Step + +func (s StepList) String() string { + names := make([]string, len(s)) + for i, step := range s { + names[i] = step.s.name() + } + return strings.Join(names, " ") +} + +type UnknownStepNameError string + +func (e UnknownStepNameError) Error() string { + return fmt.Sprintf("unknown decrypt loop step name %q", string(e)) +} + // for diskusage.go -func (s Step) name() string { - return s.s.name() +func (s StepList) runBlock(c cipher.Block, b []byte) { + for _, step := range s { + step.s.do(c, b) + } } -func (s Step) do(c cipher.Block, b []byte) { - s.s.do(c, b) +func stepListFromString(s string) (StepList, error) { + names := strings.Split(s, " ") + steps := make(StepList, len(names)) + for i, name := range names { + step, ok := stepsByName[name] + if !ok { + return nil, UnknownStepNameError(name) + } + steps[i] = step + } + return steps, nil } // for reallymine to use directly @@ -135,7 +163,7 @@ func (s Step) do(c cipher.Block, b []byte) { func StepUsage() string { s := "" for _, step := range validSteps { - s += fmt.Sprintf(" %s - %s\n", step.name(), step.s.desc()) + s += fmt.Sprintf(" %s - %s\n", step.s.name(), step.s.desc()) } return s } diff --git a/realcommands.go b/realcommands.go index 39ad471..0143619 100644 --- a/realcommands.go +++ b/realcommands.go @@ -34,13 +34,14 @@ func cGetDEK(d *disk.Disk) error { fmt.Printf("%s\n", formatBridge(dec.Bridge)) fmt.Printf("DEK: %s\n", formatKey(dec.DEK)) - // TODO print decryption loop steps + // TODO make this a format function? + fmt.Printf("decryption steps: %v\n", dec.Bridge.DecryptLoopSteps()) return nil } var getdek = &command.Command{ Name: "getdek", Args: []command.Arg{command.ArgDisk}, - Description: "Gets the DEK to use on %s and prints it on stdout.", + Description: "Gets the DEK and decryption steps to use on %s and prints it on stdout.", Do: cGetDEK, }