Taru Karttunen avatar Taru Karttunen committed 092ba30

Import

Comments (0)

Files changed (4)

+Copyright (c) 2012 Taru Karttunen <taruti@taruti.net>
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+package filecrypto
+
+import (
+	"bitbucket.org/taruti/go-aes-xts"
+	"bitbucket.org/taruti/pbkdf2"
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/sha1"
+	"errors"
+)
+
+type aesXts struct {
+	PlaintextMaster [32]byte
+	SlotSalt        [8][16]byte
+	SlotVal         [8][32]byte
+	C1, C2          cipher.Block
+}
+
+func newAesXts() Crypto {
+	c := aesXts{}
+	randBytes(c.PlaintextMaster[:])
+	c.C1,_ = aes.NewCipher(c.PlaintextMaster[0:16])
+	c.C2,_ = aes.NewCipher(c.PlaintextMaster[16:32])
+
+	return &c
+}
+func (c *aesXts)AddPassword(pass []byte) error {
+	for i := 0; i < 8; i++ {
+		if bytes.Equal(zeros32, c.SlotVal[i][:]) {
+			randBytes(c.SlotSalt[i][:])
+			k0 := pbkdf2.Pbkdf2(pass, c.SlotSalt[i][:], 9999, sha1.New, 16)
+			c0, _ := aes.NewCipher(k0)
+			iv := []byte{byte(i), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+			cbc := cipher.NewCBCEncrypter(c0, iv)
+			cbc.CryptBlocks(c.SlotVal[i][:], c.PlaintextMaster[:])
+			return nil
+		}
+	}
+	return errors.New("AddPassword: No free slots")
+}
+
+func (c*aesXts)Encrypt(data []byte, eoff int64) {
+	aes_xts.Encrypt(c.C2, c.C1, uint64(eoff), data, data)
+}
+func (c*aesXts)Decrypt(data []byte, eoff int64) {
+	aes_xts.Decrypt(c.C2, c.C1, uint64(eoff), data, data)
+}
+
+func (c *aesXts) Header() []byte {
+	ss := make([]byte, 16*4096)
+	// FIXME should be pseudorandom-filled?
+	for i := 0; i < 16; i++ {
+		for j := 0; j < 8; j++ {
+			ss[(4096 * i)] = AlgoAesXts
+			ss[(4096*i)+(4*j)+1] = c.SlotSalt[j][i]
+			ss[(4096*i)+(4*j)+2] = c.SlotVal[j][i]
+			ss[(4096*i)+(4*j)+3] = c.SlotVal[j][i+16]
+		}
+	}
+	return ss
+}
+
+func loadAesXts(ss []byte, pf func()[]byte, test func(Crypto)bool) Crypto {
+	c := new(aesXts)
+	for i:=0; i<16; i++ {
+		for j:=0; j<8; j++ {
+			c.SlotSalt[j][i]   = ss[(4096*i)+(4*j)+1]
+			c.SlotVal[j][i]    = ss[(4096*i)+(4*j)+2]
+			c.SlotVal[j][i+16] = ss[(4096*i)+(4*j)+3]
+		}
+	}
+
+	for {
+		pass := pf()
+		for i:=0; i<8; i++ {
+			k0 := pbkdf2.Pbkdf2(pass, c.SlotSalt[i][:], 9999, sha1.New, 16)
+			c0, _ := aes.NewCipher(k0)
+			iv := []byte{byte(i), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+			cbc := cipher.NewCBCDecrypter(c0, iv)
+			cbc.CryptBlocks(c.PlaintextMaster[:], c.SlotVal[i][:])
+			c.C1,_ = aes.NewCipher(c.PlaintextMaster[0:16])
+			c.C2,_ = aes.NewCipher(c.PlaintextMaster[16:32])
+			if test(c) { return c }
+		}
+	}
+	panic("Not reached")	
+}
+package filecrypto
+
+import "crypto/rand"
+import "io"
+
+type Crypto interface {
+	AddPassword(pass []byte) error
+	Header() []byte
+	Encrypt(block []byte, sectorNumber int64)
+	Decrypt(block []byte, sectorNumber int64)
+}
+
+const (
+	AlgoAesXts = iota
+	AlgoPlain
+	HeaderSize = 64*1024
+)
+
+var zeros32 = make([]byte, 32)
+
+func randBytes(data []byte) {
+	_, e := io.ReadFull(rand.Reader, data)
+	if e != nil {
+		panic("Cannot read from random source!")
+	}
+}
+
+func LoadCrypto(headerBytes []byte, passwordFunc func()[]byte, testDecryptionOk func(Crypto)bool) Crypto {
+	switch headerBytes[0] {
+	case AlgoAesXts:
+		return loadAesXts(headerBytes,passwordFunc,testDecryptionOk)
+	case AlgoPlain:
+		return plain{}
+	}
+	return nil
+}
+
+func New(algorithm int) Crypto {
+	switch algorithm {
+		case AlgoAesXts:
+			return newAesXts()
+		case AlgoPlain:
+			return plain{}
+	}
+	return nil
+}
+package filecrypto
+
+type plain struct{}
+
+func (plain)AddPassword([]byte) error {
+	return nil
+}
+
+func (plain)Header() []byte {
+	return make([]byte,64*1024)
+}
+
+func (plain)Encrypt(block []byte, sectorNumber int64) {
+}
+
+func (plain)Decrypt(block []byte, sectorNumber int64) {
+}
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.