/// <summary> /// Parses a password history from the database serialized format which is: /// smmnnddddddddllll[passsword] ... /// 's' is a decimal status. /// 'mm' is a hex max number of password history entries /// 'nn' is a hex number of passwords in this list /// The following is repeated 'nn' times: /// 'dddddddd' is a hex representation of 32-bit unix time when this password was changed. /// 'llll' is a hex representation of 16-bit length of the password that follows. /// [password] is the string of the password. /// </summary> /// <param name="serialized">The serialized string</param> /// <returns>The decoded password history</returns> public static PasswordSafePasswordHistory Parse( string serialized) { if (serialized == null) { throw new ArgumentNullException("serialized"); } var history = new PasswordSafePasswordHistory(); if (serialized.Length < 5) { return(history); } history.Status = byte.Parse(serialized.Substring(0, 1), NumberStyles.Integer, CultureInfo.InvariantCulture); history.MaxHistory = byte.Parse(serialized.Substring(1, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); var numberOfPasswords = int.Parse(serialized.Substring(3, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); var currentIndex = 5; for (var i = 0; i < numberOfPasswords; ++i) { var unixTimeChanged = int.Parse(serialized.Substring(currentIndex, 8), NumberStyles.HexNumber, CultureInfo.InvariantCulture); var passwordChangedUtc = PasswordSafeUtility.GetUtcFromUnixTime(unixTimeChanged); currentIndex += 8; var passwordLength = int.Parse(serialized.Substring(currentIndex, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture); currentIndex += 4; var password = serialized.Substring(currentIndex, passwordLength); currentIndex += passwordLength; history.PasswordHistoryAdd(new PasswordSafePassword(password, passwordChangedUtc)); } return(history); }
/// <summary> /// Reads one data record. /// </summary> /// <returns>The record</returns> private PasswordSafeRecord ReadRecord() { var fields = ReadGenericRecord(); if (fields == null) { return(null); } var record = new PasswordSafeRecord(); var endSeen = false; foreach (var field in fields) { if (endSeen) { throw new InvalidDataException("The END filed must be last in the header"); } var data = field.DataBuffer(); switch ((PasswordSafeRecordTypeCode)field.Type) { case PasswordSafeRecordTypeCode.NAME: throw new InvalidDataException("The NAME field type is not allowed here."); case PasswordSafeRecordTypeCode.UUID: if (data.Length != 16) { throw new InvalidDataException("UUID field length wrong"); } record.Uuid = new Guid(data); break; case PasswordSafeRecordTypeCode.GROUP: record.Group = Encoding.UTF8.GetString(data, 0, data.Length); //.UTF8.GetString(data,0,data.Length); break; case PasswordSafeRecordTypeCode.TITLE: record.Title = Encoding.UTF8.GetString(data, 0, data.Length); break; case PasswordSafeRecordTypeCode.USER: record.User = Encoding.UTF8.GetString(data, 0, data.Length); break; case PasswordSafeRecordTypeCode.NOTES: record.Notes = Encoding.UTF8.GetString(data, 0, data.Length); break; case PasswordSafeRecordTypeCode.PASSWORD: record.PasswordValue = Encoding.UTF8.GetString(data, 0, data.Length); break; case PasswordSafeRecordTypeCode.CTIME: record.TimeRecordCreatedUtc = GetUtcFromUnixTime(data); break; case PasswordSafeRecordTypeCode.PMTIME: record.TimePasswordModifiedUtc = GetUtcFromUnixTime(data); break; case PasswordSafeRecordTypeCode.ATIME: record.TimeRecordAccessedUtc = GetUtcFromUnixTime(data); break; case PasswordSafeRecordTypeCode.LTIME: record.TimePasswordExpiresUtc = GetUtcFromUnixTime(data); break; case PasswordSafeRecordTypeCode.POLICY: throw new InvalidDataException("The POLICY field type is not allowed here."); case PasswordSafeRecordTypeCode.RMTIME: record.TimeRecordModifiedUtc = GetUtcFromUnixTime(data); break; case PasswordSafeRecordTypeCode.URL: record.ResourceLocator = Encoding.UTF8.GetString(data, 0, data.Length); break; case PasswordSafeRecordTypeCode.AUTOTYPE: record.AutoType = Encoding.UTF8.GetString(data, 0, data.Length); break; case PasswordSafeRecordTypeCode.PWHIST: var serializedHistory = Encoding.UTF8.GetString(data, 0, data.Length); record.PasswordHistory = PasswordSafePasswordHistory.Parse(serializedHistory); break; case PasswordSafeRecordTypeCode.END: endSeen = true; break; default: record.UnknownFieldEntriesAdd(field); break; } } return(record); }