/// <summary> /// Initializes a new instance of the <see cref="KeyWrapSalt"/> class. /// </summary> /// <param name="length">The length of the salt in bytes. It must be a valid AES key length.</param> public KeyWrapSalt(int length) { if (!AesKey.IsValidKeyLength(length)) { throw new InternalErrorException("A key wrap salt length must at least be equal to a valid AES key length."); } _salt = OS.Current.GetRandomBytes(length); }
/// <summary> /// Unwrap an AES Key Wrapped-key /// </summary> /// <param name="wrapped">The full wrapped data, the length of a key + 8 bytes</param> /// <returns>The unwrapped key data, or a zero-length array if the unwrap was unsuccessful due to wrong key</returns> public byte[] Unwrap(byte[] wrapped) { if (_aes == null) { throw new ObjectDisposedException("_aes"); } int wrappedKeyLength = wrapped.Length - A.Length; if (!AesKey.IsValidKeyLength(wrappedKeyLength)) { throw new InternalErrorException("The length of the wrapped data must be exactly the length of a valid key length plus 8 bytes"); } wrapped = (byte[])wrapped.Clone(); ICryptoTransform decryptor = _aes.CreateDecryptor(); byte[] block = new byte[decryptor.InputBlockSize]; // wrapped[0..7] contains the A (IV) of the Key Wrap algorithm, // the rest is 'Wrapped Key Data', R[1], ..., R[n]. We do the transform in-place. for (long j = _iterations - 1; j >= 0; --j) { for (int i = wrappedKeyLength / 8; i >= 1; --i) { long t = ((wrappedKeyLength / 8) * j) + i; // MSB(B) = A XOR t Array.Copy(wrapped, 0, block, 0, 8); switch (_mode) { case KeyWrapMode.Specification: block.Xor(0, t.GetBigEndianBytes(), 0, 8); break; case KeyWrapMode.AxCrypt: block.Xor(0, t.GetLittleEndianBytes(), 0, 8); break; } // LSB(B) = R[i] Array.Copy(wrapped, i * 8, block, 8, 8); // B = AESD(K, X xor t | R[i]) where t = (n * j) + i byte[] b = decryptor.TransformFinalBlock(block, 0, decryptor.InputBlockSize); // A = MSB(B) Array.Copy(b, 0, wrapped, 0, 8); // R[i] = LSB(B) Array.Copy(b, 8, wrapped, i * 8, 8); } } if (!wrapped.IsEquivalentTo(0, A, 0, A.Length)) { return(new byte[0]); } byte[] unwrapped = new byte[_key.Length]; Array.Copy(wrapped, A.Length, unwrapped, 0, unwrapped.Length); return(unwrapped); }
/// <summary> /// Initializes a new instance of the <see cref="KeyWrapSalt"/> class. /// </summary> /// <param name="length">The salt. It must be a valid AES key length.</param> public KeyWrapSalt(byte[] salt) { if (salt == null) { throw new ArgumentNullException("salt"); } if (salt.Length != 0 && !AesKey.IsValidKeyLength(salt.Length)) { throw new InternalErrorException("A key wrap salt length must at least be equal to a valid AES key length."); } _salt = (byte[])salt.Clone(); }