Secure data storage application written in C. Follows this playlist on YouTube
Variable Name | Purpose | Source |
---|
File Name | Purpose | Organization | Encryption |
---|---|---|---|
iv.dv | Store IV's and salts |
|
none |
data.dv | Store encrypted data |
|
AES_256(k = dataKey, iv = dataIV) |
map.dv | Map entry names to entry id |
|
AES_256(k = dataKey, iv = mapIV) |
btree.dv | Map entry ids to initial block in data.dv |
|
AES_256(k = dataKey, iv = btreeIV) |
categories.dv | Map category ids to category name |
|
AES_256(k = dataKey, iv = categoryIV) |
pwd.dv | Store the hash of the user's password |
|
SHA3_512(salt = userPwdSalt) |
datakey.dv | Store the data key |
|
AES_256(k = kek, iv = dataKeyIV) |
All numerical id's are represented as unsigned values
Input: userPwd
- Create all files iv.dv data.dv map.dv btree.dv categories.dv pwd.dv datakey.dv
- Generate salts and IV's, output into iv.dv
userPwdSalt = randomBytes(16)
kekSalt = randomBytes(16)
dataKeyIV = randomBytes(16)
dataIV = randomBytes(16)
mapIV = randomBytes(16)
btreeIV = randomBytes(16)
categoryIV = randomBytes(16)
write("iv.dv", userPwdSalt, kekSalt, dataKeyIV, dataIV, mapIV, btreeIV, categoryIV)
- Process userPwd and generate dataKey
write("pwd.dv", SHA3_512(salt = userPwdSalt, txt = userPwd))
dataKey = randomBytes(16)
keyEncryptionKey = PBKDF2(k = userPwd, salt = kekSalt, dklen = 32)
write("datakey.dv", AESenc_256(k = keyEncryptionKey, txt = dataKey, iv = dataKeyIV))
Input: userPwd
- Read salts and iv's from iv.dv
// sequential list
randList = content("iv.dv")
userPwdSalt = randList[0:16)
kekSalt = randList[16:32)
dataKeyIV = randList[32:48)
dataIV = randList[48:64)
mapIV = randList[64:80)
btreeIV = randList[80:96)
categoryIV = randList[96:112)
- Validate userPwd
// compare hashes
inputHash = SHA3_512(salt = userPwdSalt, txt = userPwd)
assertEquals(inputHash, contents("pwd.dv"))
- Decrypt dataKey
// derive key encryption key from userPwd
keyEncryptionKey = PBKDF2(k = userPwd, salt = kekSalt, dklen = 32)
free(userPwd)
// decrypt dataKey
dataKey = AESdec_256(k = keyEncryptionKey, txt = contents("dataKey.dv"), iv = dataKeyIV)
free(keyEncryptionKey)
- Generate AES key schedule
// save in memory for use throughout program when decrypting data
keySchedule = AESgenKeySchedule_256(k = dataKey)
- Allocate memory to maps
nameIdMap = avl_tree()
idIdxMap = btree()
categoryIdMap = avl_tree()
- Call the Load sequence
- Call the Save sequence
- free memory
free(dataKey)
free(keySchedule)
btree_free(entryMap)
avl_free(nameMap)
avl_free(categoryMap)
maxId = 0
- Decrypt and load btree.dv
btreeStr = AESdec_256(k = dataKey, txt = contents("btree.dv"), iv = btreeIV)
for each entry
// parse 2 4-byte numerical values for id and initialBlock
read 4 chars
id = val({chars}, base = 256)
maxId = MAX(id, maxId)
read 4 chars
initialBlock = val({chars}, base = 256)
// insert key value pair
insert (id, initialBlock) into idIdxMap
- Decrypt and load map.dv
mapStr = AESdec_256(k = dataKey, txt = contents("map.dv"), iv = mapIV)
for each entry
read chars until \0
name = {chars}
// parse 4 byte unsigned numerical value for id
read 4 chars
id = val({chars}, base = 256)
// insert key value pair
insert (name, id) into nameIdMap
- Decrypt and load categories.dv
categoriesStr = AESdec_256(k = dataKey, txt = contents("categories.dv"), iv = categoryIV)
for each entry
// parse 1 byte unsigned numerical value for id
read 1 char
id = val(char, base = 256)
read chars until \0
name = {chars}
// insert key value pair
insert (name, id) into categoryIdMap
- Stringify and encrypt nameMap
for each entry
// stringify id and concatenate to name
entryStr = entry.name, \0, smallEndian(entry.id)
concatenate entryStr to nameMapStr
write AESenc_256(k = dataKey, txt = entryStr, iv = mapIV) into map.dv
- Stringify and encrypt entryMap
for each entry
// stringify id and initial block and concatenate
entryStr = smallEndian(entry.id), smallEndian(entry.initialBlock)
concatenate entryStr to btreeStr
write AESenc_256(k = dataKey, txt = btreeStr, iv = btreeIV) into btree.dv
- Stringify and encrypt cateogriesMap
for each entry
// stringify id and concatenate to name
entryStr = entry.name, \0, smallEndian(entry.id)
concatenate entryStr to categoriesStr
write AESenc_256(k = dataKey, txt = categoriesStr, iv = categoriesIV) into categories.dv
- Write salts
write userPwdSalt + kekSalt + dataKeyIV + dataIV + mapIV + btreeIV + categoryIV into iv.dv
Input: name
- Insert into name map
insert (name, ++maxId) into nameIdMap
- Create initial block
initBlock = filelen(data.dv) / 16 + 1
block = 0, randomBytes(11), smallEndian(0)
increment dataIV by initBlock
append AESenc_256(k = dataKey, txt = block, iv = dataIV) to data.dv
- Insert into index map
insert (maxId, initBlock) into idIdxMap
Input: name, category
- Find the category id
catId = categoryIdMap(category)
if catId = 0
return NULL
- Find the entry id
id = nameIdMap(name)
if id = 0
return NULL
- Read entry data
previousBlock = 0
currentBlock = idIdxMap(id)
while true
increment dataIV by currentBlock - previousBlock
blk = AESdec_256(k = dataKey, txt = block(data.dv, currentBlock), iv = dataIV)
completed = false
for i in [0:12)
if curCat = 0
curCat = blk[i]
id curCat = 0
return NULL
else
read {chars} until 0 or end
if curCat = catId
// add characters to string
retChars += {chars}
if blk[i] = 0
completed = true
break
else
continue
if completed
break
previousBlock = currentBlock
currentBlock = val(input[12:16), base = 256)
if currentBlock = 0
break
if retChars
return retChars
else
return NULL
Input: name, category, new data
- Find the category id
catId = categoryIdMap(category)
if catId = 0
catId = ++maxCatId
insert (category, catId) into categoryIdMap
- Find the entry id
id = nameIdMap(name)
if id = 0
// did not find name
id = call Create Entry sequence
- Write data
previousBlock = 0
currentBlock = idIdxMap(id)
while true
increment dataIV by currentBlock - previousBlock
blk = AESdec_256(k = dataKey, txt = block(data.dv, currentBlock), iv = dataIV)
modified = false
for i in [0:12)
cat = blk[i]
if cat = 0
blk[i] = catId
if i != 11
write new data into blk[i+1:12)
modified = true
if more data
nextBlock = filelen(data.dv) / 16 + 1
blk[12:16) = smallEndian(nextBlock)
if modified
write AES_enc(k = dataKey, txt = blk, iv = dataIV) into data.dv at currentBlock
if nextBlock != 0
previousBlock = currentBlock
currentBlock = nextBlock
else
break