Beispiel #1
0
// ReadKeyfile reads a randomly generated and encrypted AES-256 key from the
// file with the given filename and returns it in unencrypted form.
// The key is protected by a passphrase, which is processed by PBKDF2 to
// derive the AES-256 key to decrypt the generated key.
func ReadKeyfile(filename string, passphrase []byte) (key []byte, err error) {
	// open keyfile
	keyfile, err := os.Open(filename)
	if err != nil {
		return nil, log.Error(err)
	}
	defer keyfile.Close()
	// read iter and convert to int
	var biter = make([]byte, 8)
	if _, err := keyfile.Read(biter); err != nil {
		return nil, log.Error(err)
	}
	uiter := encode.ToUint64(biter)
	if uiter > 2147483647 {
		return nil, log.Errorf("encdb: ReadKeyfile: invalid iter value")
	}
	iter := int(uiter)
	// read salt
	var salt = make([]byte, 32)
	if _, err := keyfile.Read(salt); err != nil {
		return nil, log.Error(err)
	}
	// read encrypted key
	var encKey = make([]byte, 16+32)
	if _, err := keyfile.Read(encKey); err != nil {
		return nil, log.Error(err)
	}
	// compute derived key from passphrase
	dk := pbkdf2.Key([]byte(passphrase), salt, iter, 32, sha256.New)
	// decrypt key
	return cipher.AES256CBCDecrypt([]byte(dk), encKey), nil
}
Beispiel #2
0
func (ce *CryptEngine) lookupHashChain(id string) error {
	// map identity
	mappedID, domain, err := identity.MapPlus(id)
	if err != nil {
		return err
	}
	// get JSON-RPC client
	client, _, err := ce.cache.Get(domain, ce.keydPort, ce.keydHost, ce.homedir,
		"KeyHashchain.LookupUID")
	if err != nil {
		return err
	}
	// Call KeyHashchain.LookupUID
	content := make(map[string]interface{})
	content["Identity"] = mappedID
	reply, err := client.JSONRPCRequest("KeyHashchain.LookupUID", content)
	if err != nil {
		return err
	}
	hcPositions, ok := reply["HCPositions"].([]interface{})
	if !ok {
		if _, ok := reply["HCPositions"].(interface{}); !ok {
			return log.Errorf("lookup found no entry of id '%s'", id)
		}
		return log.Error("cryptengine: lookup ID reply has the wrong type")
	}
	var TYPE, NONCE, HashID, CrUID, UIDIndex []byte
	var matchFound bool
	for k, v := range hcPositions {
		hcPosFloat, ok := v.(float64)
		if !ok {
			return log.Errorf("cryptengine: lookup ID reply position entry %d has the wrong type", k)
		}
		hcPos := uint64(hcPosFloat)
		hcEntry, err := ce.keyDB.GetHashChainEntry(domain, hcPos)
		if err != nil {
			return err
		}
		_, TYPE, NONCE, HashID, CrUID, UIDIndex, err = hashchain.SplitEntry(hcEntry)
		if err != nil {
			return err
		}
		if !bytes.Equal(TYPE, hashchain.Type) {
			return log.Error("cryptengine: invalid entry type")
		}

		// Compute k1, k2 = CKDF(NONCE)
		k1, k2 := cipher.CKDF(NONCE)

		// Compute: HashIDTest = HASH(k1 | Identity)
		tmp := make([]byte, len(k1)+len(mappedID))
		copy(tmp, k1)
		copy(tmp[len(k1):], mappedID)
		HashIDTest := cipher.SHA256(tmp)

		// If NOT: HashID == HashIDTest: Continue
		if !bytes.Equal(HashID, HashIDTest) {
			return log.Error("cryptengine: lookup ID returned bogus position")
		}
		log.Debugf("cryptengine: UIDIndex=%s", base64.Encode(UIDIndex))

		// Check UID already exists in keyDB
		_, pos, found, err := ce.keyDB.GetPublicUID(mappedID, hcPos)
		if err != nil {
			return err
		}
		if found && pos == hcPos {
			// UID exists already -> skip entry
			matchFound = true
			continue
		}

		// Compute: IDKEY = HASH(k2 | Identity)
		tmp = make([]byte, len(k2)+len(mappedID))
		copy(tmp, k2)
		copy(tmp[len(k2):], mappedID)
		IDKEY := cipher.SHA256(tmp)

		// Fetch from Key Repository: UIDMessageReply = GET(UIDIndex)
		msgReply, err := ce.fetchUID(domain, UIDIndex)
		if err != nil {
			return err
		}

		// Decrypt UIDHash = AES_256_CBC_Decrypt( IDKEY, CrUID)
		UIDHash := cipher.AES256CBCDecrypt(IDKEY, CrUID)
		log.Debugf("cryptengine: UIDHash=%s", base64.Encode(UIDHash))

		// Decrypt UIDMessageReply.UIDMessage with UIDHash
		index, uid, err := msgReply.Decrypt(UIDHash)
		if err != nil {
			return err
		}
		log.Debugf("cryptengine: UIDMessage=%s", uid.JSON())

		// Check index
		if !bytes.Equal(index, UIDIndex) {
			return log.Errorf("cryptengine: index != UIDIndex")
		}

		// Verify self signature
		if err := uid.VerifySelfSig(); err != nil {
			return log.Error(err)
		}

		// Verify server signature
		if err := ce.verifyServerSig(uid, msgReply, hcPos); err != nil {
			return err
		}

		// TODO: make sure the whole chain of UIDMessages is valid

		// Store UIDMessage
		if err := ce.keyDB.AddPublicUID(uid, hcPos); err != nil {
			return err
		}
		matchFound = true

		// If no further entry can be found, the latest UIDMessage entry has been found
	}

	if matchFound {
		return nil
	}

	return log.Errorf("lookup found no entry of id '%s'", id)
}
Beispiel #3
0
// searchHashChain searches the local hash chain corresponding to the given id
// for the id. It talks to the corresponding key server to retrieve necessary
// UIDMessageReplys and stores found UIDMessages in the local keyDB.
func (ce *CryptEngine) searchHashChain(id string, searchOnly bool) error {
	// map identity
	mappedID, domain, err := identity.MapPlus(id)
	if err != nil {
		return err
	}
	// make sure we have a hashchain for the given domain
	max, found, err := ce.keyDB.GetLastHashChainPos(domain)
	if err != nil {
		return err
	}
	if !found {
		return log.Errorf("no hash chain entries found for domain '%s'", domain)
	}

	var TYPE, NONCE, HashID, CrUID, UIDIndex []byte
	var matchFound bool
	for i := uint64(0); i <= max; i++ {
		hcEntry, err := ce.keyDB.GetHashChainEntry(domain, i)
		if err != nil {
			return err
		}
		log.Debugf("cryptengine: search hash chain entry %d: %s", i, hcEntry)

		_, TYPE, NONCE, HashID, CrUID, UIDIndex, err = hashchain.SplitEntry(hcEntry)
		if err != nil {
			return err
		}
		if !bytes.Equal(TYPE, hashchain.Type) {
			return log.Error("cryptengine: invalid hash chain entry type")
		}

		// Compute k1, k2 = CKDF(NONCE)
		k1, k2 := cipher.CKDF(NONCE)

		// Compute: HashIDTest = HASH(k1 | Identity)
		tmp := make([]byte, len(k1)+len(mappedID))
		copy(tmp, k1)
		copy(tmp[len(k1):], mappedID)
		HashIDTest := cipher.SHA256(tmp)

		// If NOT: HashID == HashIDTest: Continue
		if !bytes.Equal(HashID, HashIDTest) {
			continue
		}
		if searchOnly {
			return nil
		}
		log.Debugf("cryptengine: UIDIndex=%s", base64.Encode(UIDIndex))

		// Check UID already exists in keyDB
		_, pos, found, err := ce.keyDB.GetPublicUID(mappedID, i)
		if err != nil {
			return err
		}
		if found && pos == i {
			// UID exists already -> skip entry
			matchFound = true
			continue
		}

		// Compute: IDKEY = HASH(k2 | Identity)
		tmp = make([]byte, len(k2)+len(mappedID))
		copy(tmp, k2)
		copy(tmp[len(k2):], mappedID)
		IDKEY := cipher.SHA256(tmp)

		// Fetch from Key Repository: UIDMessageReply = GET(UIDIndex)
		msgReply, err := ce.fetchUID(domain, UIDIndex)
		if err != nil {
			return err
		}

		// Decrypt UIDHash = AES_256_CBC_Decrypt( IDKEY, CrUID)
		UIDHash := cipher.AES256CBCDecrypt(IDKEY, CrUID)
		log.Debugf("cryptengine: UIDHash=%s", base64.Encode(UIDHash))

		// Decrypt UIDMessageReply.UIDMessage with UIDHash
		index, uid, err := msgReply.Decrypt(UIDHash)
		if err != nil {
			return err
		}
		log.Debugf("cryptengine: UIDMessage=%s", uid.JSON())

		// Check index
		if !bytes.Equal(index, UIDIndex) {
			return log.Errorf("cryptengine: index != UIDIndex")
		}

		// Verify self signature
		if err := uid.VerifySelfSig(); err != nil {
			return log.Error(err)
		}

		// Verify server signature
		if err := ce.verifyServerSig(uid, msgReply, i); err != nil {
			return err
		}

		// TODO: make sure the whole chain of UIDMessages is valid

		// Store UIDMessage
		if err := ce.keyDB.AddPublicUID(uid, i); err != nil {
			return err
		}
		matchFound = true

		// If no further entry can be found, the latest UIDMessage entry has been found
	}

	if matchFound {
		return nil
	}

	return log.Errorf("no hash chain entry found of id '%s'", id)
}