/// <summary> /// Updates contents of encrypted file using another unencrypted file. Iv and signature of the file is also changed. /// </summary> /// <param name="updateFile">Unencrypted file used to update encrypted file.</param> /// <param name="oldEncryptedFile">Encrypted file in its raw form that is being updated.</param> /// <param name="userId">Id of the user updating the file. File can only be updated by a file owner.</param> /// <param name="userPrivateKey">Private RSA key of the user updating the file.</param> /// <returns>Updated encrypted file in its raw form.</returns> public byte[] Update(OriginalFile updateFile, byte[] oldEncryptedFile, int userId, RSAParameters userPrivateKey) { if (userId != GetFileOwnerId(oldEncryptedFile)) { throw new Exception("Only a file owner can modify its content."); } var offset = 0; ((StandardInformation)Headers[0]).ParseStandardInformation(oldEncryptedFile, offset); // update altered and read time of the file ((StandardInformation)Headers[0]).AlteredTime = ((StandardInformation)Headers[0]).ReadTime = DateTime.Now; // update id of the user who is updating file; ATimeUserId doesn't need to change since only a file owner can edit the file ((StandardInformation)Headers[0]).RTimeUserId = (uint)userId; offset += (int)((StandardInformation)Headers[0]).GetSaveLength(); ((SecurityDescriptor)Headers[1]).ParseSecurityDescriptor(oldEncryptedFile, ref offset); // update file signature SignFile(updateFile.FileContent, ref userPrivateKey); // update IV value new RNGCryptoServiceProvider().GetBytes(((SecurityDescriptor)Headers[1]).IV); Headers[2] = new Data(updateFile.FileContent, AlgorithmUtility.GetAlgorithmFromNameSignature(((SecurityDescriptor)Headers[1]).AlgorithmNameSignature, ((SecurityDescriptor)Headers[1]).GetKey(userId, userPrivateKey), ((SecurityDescriptor)Headers[1]).IV)); // update the file size ((StandardInformation)Headers[0]).TotalLength = (uint)((Data)Headers[2]).EncryptedData.Length; return(Flush()); }
/// <summary> /// Initializes a new instance of the <see cref="SecurityDescriptor"/> class with the specified parameters. /// This constructor is used when a file is first encrypted. /// </summary> /// <param name="ownerId">Users Id from the database.</param> /// <param name="algorithmNameSignature">Full name of the used symmetric algorithm.</param> /// <param name="hashAlgorithmName">Name of the hash algorithm used for file signing.</param> /// <param name="ownerPublicKey">Users public RSA key.</param> public SecurityDescriptor(int ownerId, string algorithmNameSignature, string hashAlgorithmName, RSAParameters ownerPublicKey) : base(AttributeType.SECURITY_DESCRIPTOR) { OwnerId = ownerId; AlgorithmNameSignature = algorithmNameSignature; HashAlgorithmName = hashAlgorithmName; var algorithm = AlgorithmUtility.GetAlgorithmFromNameSignature(AlgorithmNameSignature); IV = algorithm.AdditionalData; Users.Add(ownerId, new FileEncryptionKey(algorithm.Key).UnparseFek(ownerPublicKey)); }
/// <summary> /// Encrypts original file using set parameters. /// </summary> /// <param name="originalFile">Original, unencrypted file.</param> /// <param name="userId">Id of the user who is encrypting original file.</param> /// <param name="userPrivateKey">Private RSA key of the user encrypting the file.</param> /// <returns>Encrypted file in its raw form.</returns> public byte[] Encrypt(OriginalFile originalFile, int userId, RSAParameters userPrivateKey) { // create a file signature SignFile(originalFile.FileContent, ref userPrivateKey); Headers[2] = new Data(originalFile.FileContent, AlgorithmUtility.GetAlgorithmFromNameSignature(((SecurityDescriptor)Headers[1]).AlgorithmNameSignature, ((SecurityDescriptor)Headers[1]).GetKey(userId, userPrivateKey), ((SecurityDescriptor)Headers[1]).IV)); ((StandardInformation)Headers[0]).TotalLength = (uint)((Data)Headers[2]).EncryptedData.Length; return(Flush()); }
/// <summary> /// Decrypts encrypted file using parameters contained inside headers of the encrypted file. /// </summary> /// <param name="encryptedFile">Encrypted file in its raw form.</param> /// <param name="userId">Id of the user decrypting the file.</param> /// <param name="userPrivateKey">Private RSA key of the user decrypting the file.</param> /// <param name="ownerPublicKey">Public RSA key of the file owner used to verify file signature.</param> /// <returns>Decrypted file.</returns> public OriginalFile Decrypt(byte[] encryptedFile, int userId, RSAParameters userPrivateKey, RSAParameters ownerPublicKey) { var offset = 0; ((StandardInformation)Headers[0]).ParseStandardInformation(encryptedFile, offset); // update id of the user who is accessing the file ((StandardInformation)Headers[0]).ReadTime = DateTime.Now; ((StandardInformation)Headers[0]).RTimeUserId = (uint)userId; offset += (int)((StandardInformation)Headers[0]).GetSaveLength(); ((SecurityDescriptor)Headers[1]).ParseSecurityDescriptor(encryptedFile, ref offset); ((Data)Headers[2]).ParseData(encryptedFile, offset, (int)((StandardInformation)Headers[0]).TotalLength); var fileKey = ((SecurityDescriptor)Headers[1]).GetKey(userId, userPrivateKey); var fileName = NameDecryption(new AesAlgorithm(fileKey, ((SecurityDescriptor)Headers[1]).IV, "OFB")); byte[] fileContent; // Try to decrypt encrypted file. Exception will be thrown if Key, Iv or algorithm signature is changed. // Unauthorised algorithm change doesn't always have to trigger this exception and file decryption will be successful. // Such file will fail signature check test below. try { fileContent = ((Data)Headers[2]).Decrypt(AlgorithmUtility.GetAlgorithmFromNameSignature(((SecurityDescriptor)Headers[1]).AlgorithmNameSignature, fileKey, ((SecurityDescriptor)Headers[1]).IV)); } catch (Exception e) { throw new CryptographicException("Unsuccessful decryption. File has been compromised.", e); } // if file signature isn't valid Exception will be thrown! return(CheckFileSignature(fileContent, userId, ownerPublicKey) ? new OriginalFile(fileContent, fileName) : throw new CryptographicException("File integrity has been compromised.")); }