updateEncKey method

Future<String> updateEncKey(
  1. String plainPrevEncKey,
  2. String plainNewEncKey
)

Update/change encryption key Need to re-encrypt all the encrypted files using the new key

Implementation

Future<String> updateEncKey(
    String plainPrevEncKey, String plainNewEncKey) async {
  /// Verify old encryption key before moving forward
  if (await verifyEncKey(plainPrevEncKey)) {
    /// Create hash values for old and new encrypted keys
    String newKeyHash = sha224
        .convert(utf8.encode(plainNewEncKey))
        .toString()
        .substring(0, 32);
    String newEncKey = sha256
        .convert(utf8.encode(plainNewEncKey))
        .toString()
        .substring(0, 32);
    String prevEncKey = sha256
        .convert(utf8.encode(plainPrevEncKey))
        .toString()
        .substring(0, 32);

    /// Get the previous key and the list of locations of files that are encrypted
    var keyInfo = await fetchFile(encKeyFileLoc);
    EncProfile keyFile = EncProfile(keyInfo.toString());

    String prevKeyHash = keyFile.getEncKeyHash();
    String encFileHash = keyFile.getEncFileHash();
    String encFileIv = keyFile.getEncIvVal();

    String encFilePlaintext = decryptVal(prevEncKey, encFileHash, encFileIv);
    List encFileList = jsonDecode(encFilePlaintext);

    /// Loop over each encrypted file and re-encrypt the content using
    /// new encryption key
    for (var i = 0; i < encFileList.length; i++) {
      String encFilePath = encFileList[i];
      var fileInfo = await fetchFile(encFilePath);
      EncProfile encFile = EncProfile(fileInfo.toString());
      String encFileCont = encFile.getEncFileCont();
      String encFileIv = encFile.getEncIvVal();

      String plainFileCont = decryptVal(prevEncKey, encFileCont, encFileIv);
      List newEncFileRes = encryptVal(newEncKey, plainFileCont);
      String newEncFileCont = newEncFileRes[0];
      String newEncIv = newEncFileRes[1];

      String encFileUrl = webId.replaceAll('profile/card#me', encFilePath);

      // Update encrypted value
      String dPopToken =
          genDpopToken(encFileUrl, rsaKeyPair, publicKeyJwk, 'PATCH');
      String fileUpdateQuery = genSparqlQuery(
          'UPDATE', '', encValPred, newEncFileCont,
          prevObject: encFileCont);
      String fileContupdate =
          await runQuery(encFileUrl, dPopToken, fileUpdateQuery);

      // Update IV value
      String dPopTokenIv =
          genDpopToken(encFileUrl, rsaKeyPair, publicKeyJwk, 'PATCH');
      String fileUpdateQueryIv = genSparqlQuery(
          'UPDATE', '', ivValPred, newEncIv,
          prevObject: encFileIv);
      String fileContupdateIv =
          await runQuery(encFileUrl, dPopTokenIv, fileUpdateQueryIv);

      if (fileContupdate == 'ok' && fileContupdateIv == 'ok') {
        continue;
      } else {
        throw Exception('Failed to update encrypted file $encFilePath.');
      }
    }

    /// Update the encryption key hash with new key
    String encKeyUrl = webId.replaceAll('profile/card#me', encKeyFileLoc);
    String dPopToken =
        genDpopToken(encKeyUrl, rsaKeyPair, publicKeyJwk, 'PATCH');

    String updateQuery = genSparqlQuery('UPDATE', '', encKeyPred, newKeyHash,
        prevObject: prevKeyHash);

    String updateResponse = await runQuery(encKeyUrl, dPopToken, updateQuery);

    if (updateResponse == 'ok') {
      /// Update the list of locations of the encrypted files
      List encFileNewRes = encryptVal(newEncKey, encFilePlaintext);
      String encFileHashNew = encFileNewRes[0];
      String encFileIvNew = encFileNewRes[1];

      // Update encrypted value
      String dPopToken =
          genDpopToken(encKeyUrl, rsaKeyPair, publicKeyJwk, 'PATCH');
      String updateQuery = genSparqlQuery(
          'UPDATE', '', encFilePred, encFileHashNew,
          prevObject: encFileHash);
      String updateResponse =
          await runQuery(encKeyUrl, dPopToken, updateQuery);

      // Update IV value
      String dPopTokenIv =
          genDpopToken(encKeyUrl, rsaKeyPair, publicKeyJwk, 'PATCH');
      String updateQueryIv = genSparqlQuery(
          'UPDATE', '', ivValPred, encFileIvNew,
          prevObject: encFileIv);
      String updateResponseIv =
          await runQuery(encKeyUrl, dPopTokenIv, updateQueryIv);

      if (updateResponse == 'ok' && updateResponseIv == 'ok') {
        removeEncKeyStorage();

        /// Remove previous key from local storage
        setEncKeyStorage(newEncKey);

        /// Set new key to local storage
        return updateResponse;
      } else {
        throw Exception('Failed to update encrypted file locations.');
      }
    } else {
      throw Exception('Failed to update new encryption key.');
    }
  } else {
    throw Exception('Failed to verify the previous encryption key.');
  }
}