Example #1
0
  @Override
  public PwDatabaseV4 openDatabase(
      InputStream inStream, String password, String keyfile, UpdateStatus status)
      throws IOException, InvalidDBException {

    db = createDB();

    PwDbHeaderV4 header = new PwDbHeaderV4(db);

    hashOfHeader = header.loadFromFile(inStream);

    db.setMasterKey(password, keyfile);
    db.makeFinalKey(header.masterSeed, header.transformSeed, (int) db.numKeyEncRounds);

    // Attach decryptor
    Cipher cipher;
    try {
      cipher =
          CipherFactory.getInstance(
              db.dataCipher, Cipher.DECRYPT_MODE, db.finalKey, header.encryptionIV);
    } catch (NoSuchAlgorithmException e) {
      throw new IOException("Invalid algorithm.");
    } catch (NoSuchPaddingException e) {
      throw new IOException("Invalid algorithm.");
    } catch (InvalidKeyException e) {
      throw new IOException("Invalid algorithm.");
    } catch (InvalidAlgorithmParameterException e) {
      throw new IOException("Invalid algorithm.");
    }

    InputStream decrypted = new BetterCipherInputStream(inStream, cipher, 50 * 1024);
    LEDataInputStream dataDecrypted = new LEDataInputStream(decrypted);
    byte[] storedStartBytes = null;
    try {
      storedStartBytes = dataDecrypted.readBytes(32);
      if (storedStartBytes == null || storedStartBytes.length != 32) {
        throw new InvalidPasswordException();
      }
    } catch (IOException e) {
      throw new InvalidPasswordException();
    }

    if (!Arrays.equals(storedStartBytes, header.streamStartBytes)) {
      throw new InvalidPasswordException();
    }

    HashedBlockInputStream hashed = new HashedBlockInputStream(dataDecrypted);

    InputStream decompressed;
    if (db.compressionAlgorithm == PwCompressionAlgorithm.Gzip) {
      decompressed = new GZIPInputStream(hashed);
    } else {
      decompressed = hashed;
    }

    if (header.protectedStreamKey == null) {
      assert (false);
      throw new IOException("Invalid stream key.");
    }

    randomStream =
        PwStreamCipherFactory.getInstance(header.innerRandomStream, header.protectedStreamKey);

    if (randomStream == null) {
      throw new ArcFourException();
    }

    ReadXmlStreamed(decompressed);

    return db;
  }
Example #2
0
  private KdbContext ReadXmlElement(KdbContext ctx, XmlPullParser xpp)
      throws XmlPullParserException, IOException, InvalidDBException {
    String name = xpp.getName();
    switch (ctx) {
      case Null:
        if (name.equalsIgnoreCase(ElemDocNode)) {
          return SwitchContext(ctx, KdbContext.KeePassFile, xpp);
        } else ReadUnknown(xpp);
        break;

      case KeePassFile:
        if (name.equalsIgnoreCase(ElemMeta)) {
          return SwitchContext(ctx, KdbContext.Meta, xpp);
        } else if (name.equalsIgnoreCase(ElemRoot)) {
          return SwitchContext(ctx, KdbContext.Root, xpp);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case Meta:
        if (name.equalsIgnoreCase(ElemGenerator)) {
          ReadString(xpp); // Ignore
        } else if (name.equalsIgnoreCase(ElemHeaderHash)) {
          String encodedHash = ReadString(xpp);
          if (!EmptyUtils.isNullOrEmpty(encodedHash) && (hashOfHeader != null)) {
            byte[] hash = Base64Coder.decode(encodedHash);
            if (!Arrays.equals(hash, hashOfHeader)) {
              throw new InvalidDBException();
            }
          }
        } else if (name.equalsIgnoreCase(ElemDbName)) {
          db.name = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemDbNameChanged)) {
          db.nameChanged = ReadTime(xpp);
        } else if (name.equalsIgnoreCase(ElemDbDesc)) {
          db.description = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemDbDescChanged)) {
          db.descriptionChanged = ReadTime(xpp);
        } else if (name.equalsIgnoreCase(ElemDbDefaultUser)) {
          db.defaultUserName = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemDbDefaultUserChanged)) {
          db.defaultUserNameChanged = ReadTime(xpp);
        } else if (name.equalsIgnoreCase(ElemDbColor)) {
          // TODO: Add support to interpret the color if we want to allow changing the database
          // color
          db.color = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemDbMntncHistoryDays)) {
          db.maintenanceHistoryDays = ReadUInt(xpp, DEFAULT_HISTORY_DAYS);
        } else if (name.equalsIgnoreCase(ElemDbKeyChanged)) {
          db.keyLastChanged = ReadTime(xpp);
        } else if (name.equalsIgnoreCase(ElemDbKeyChangeRec)) {
          db.keyChangeRecDays = ReadLong(xpp, -1);
        } else if (name.equalsIgnoreCase(ElemDbKeyChangeForce)) {
          db.keyChangeForceDays = ReadLong(xpp, -1);
        } else if (name.equalsIgnoreCase(ElemMemoryProt)) {
          return SwitchContext(ctx, KdbContext.MemoryProtection, xpp);
        } else if (name.equalsIgnoreCase(ElemCustomIcons)) {
          return SwitchContext(ctx, KdbContext.CustomIcons, xpp);
        } else if (name.equalsIgnoreCase(ElemRecycleBinEnabled)) {
          db.recycleBinEnabled = ReadBool(xpp, true);
        } else if (name.equalsIgnoreCase(ElemRecycleBinUuid)) {
          db.recycleBinUUID = ReadUuid(xpp);
        } else if (name.equalsIgnoreCase(ElemRecycleBinChanged)) {
          db.recycleBinChanged = ReadTime(xpp);
        } else if (name.equalsIgnoreCase(ElemEntryTemplatesGroup)) {
          db.entryTemplatesGroup = ReadUuid(xpp);
        } else if (name.equalsIgnoreCase(ElemEntryTemplatesGroupChanged)) {
          db.entryTemplatesGroupChanged = ReadTime(xpp);
        } else if (name.equalsIgnoreCase(ElemHistoryMaxItems)) {
          db.historyMaxItems = ReadInt(xpp, -1);
        } else if (name.equalsIgnoreCase(ElemHistoryMaxSize)) {
          db.historyMaxSize = ReadLong(xpp, -1);
        } else if (name.equalsIgnoreCase(ElemEntryTemplatesGroupChanged)) {
          db.entryTemplatesGroupChanged = ReadTime(xpp);
        } else if (name.equalsIgnoreCase(ElemLastSelectedGroup)) {
          db.lastSelectedGroup = ReadUuid(xpp);
        } else if (name.equalsIgnoreCase(ElemLastTopVisibleGroup)) {
          db.lastTopVisibleGroup = ReadUuid(xpp);
        } else if (name.equalsIgnoreCase(ElemBinaries)) {
          return SwitchContext(ctx, KdbContext.Binaries, xpp);
        } else if (name.equalsIgnoreCase(ElemCustomData)) {
          return SwitchContext(ctx, KdbContext.CustomData, xpp);
        }
        break;

      case MemoryProtection:
        if (name.equalsIgnoreCase(ElemProtTitle)) {
          db.memoryProtection.protectTitle = ReadBool(xpp, false);
        } else if (name.equalsIgnoreCase(ElemProtUserName)) {
          db.memoryProtection.protectUserName = ReadBool(xpp, false);
        } else if (name.equalsIgnoreCase(ElemProtPassword)) {
          db.memoryProtection.protectPassword = ReadBool(xpp, false);
        } else if (name.equalsIgnoreCase(ElemProtURL)) {
          db.memoryProtection.protectUrl = ReadBool(xpp, false);
        } else if (name.equalsIgnoreCase(ElemProtNotes)) {
          db.memoryProtection.protectNotes = ReadBool(xpp, false);
        } else if (name.equalsIgnoreCase(ElemProtAutoHide)) {
          db.memoryProtection.autoEnableVisualHiding = ReadBool(xpp, false);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case CustomIcons:
        if (name.equalsIgnoreCase(ElemCustomIconItem)) {
          return SwitchContext(ctx, KdbContext.CustomIcon, xpp);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case CustomIcon:
        if (name.equalsIgnoreCase(ElemCustomIconItemID)) {
          customIconID = ReadUuid(xpp);
        } else if (name.equalsIgnoreCase(ElemCustomIconItemData)) {
          String strData = ReadString(xpp);
          if (strData != null && strData.length() > 0) {
            customIconData = Base64Coder.decode(strData);
          } else {
            assert (false);
          }
        } else {
          ReadUnknown(xpp);
        }
        break;

      case Binaries:
        if (name.equalsIgnoreCase(ElemBinary)) {
          String key = xpp.getAttributeValue(null, AttrId);
          if (key != null) {
            ProtectedBinary pbData = ReadProtectedBinary(xpp);
            binPool.put(key, pbData);
          } else {
            ReadUnknown(xpp);
          }
        } else {
          ReadUnknown(xpp);
        }

        break;

      case CustomData:
        if (name.equalsIgnoreCase(ElemStringDictExItem)) {
          return SwitchContext(ctx, KdbContext.CustomDataItem, xpp);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case CustomDataItem:
        if (name.equalsIgnoreCase(ElemKey)) {
          customDataKey = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemValue)) {
          customDataValue = ReadString(xpp);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case Root:
        if (name.equalsIgnoreCase(ElemGroup)) {
          assert (ctxGroups.size() == 0);
          if (ctxGroups.size() != 0) throw new IOException("Group list should be empty.");

          db.rootGroup = new PwGroupV4();
          ctxGroups.push((PwGroupV4) db.rootGroup);
          ctxGroup = ctxGroups.peek();

          return SwitchContext(ctx, KdbContext.Group, xpp);
        } else if (name.equalsIgnoreCase(ElemDeletedObjects)) {
          return SwitchContext(ctx, KdbContext.RootDeletedObjects, xpp);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case Group:
        if (name.equalsIgnoreCase(ElemUuid)) {
          ctxGroup.uuid = ReadUuid(xpp);
        } else if (name.equalsIgnoreCase(ElemName)) {
          ctxGroup.name = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemNotes)) {
          ctxGroup.notes = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemIcon)) {
          ctxGroup.icon = db.iconFactory.getIcon((int) ReadUInt(xpp, 0));
        } else if (name.equalsIgnoreCase(ElemCustomIconID)) {
          ctxGroup.customIcon = db.iconFactory.getIcon(ReadUuid(xpp));
        } else if (name.equalsIgnoreCase(ElemTimes)) {
          return SwitchContext(ctx, KdbContext.GroupTimes, xpp);
        } else if (name.equalsIgnoreCase(ElemIsExpanded)) {
          ctxGroup.isExpanded = ReadBool(xpp, true);
        } else if (name.equalsIgnoreCase(ElemGroupDefaultAutoTypeSeq)) {
          ctxGroup.defaultAutoTypeSequence = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemEnableAutoType)) {
          ctxGroup.enableAutoType = StringToBoolean(ReadString(xpp));
        } else if (name.equalsIgnoreCase(ElemEnableSearching)) {
          ctxGroup.enableSearching = StringToBoolean(ReadString(xpp));
        } else if (name.equalsIgnoreCase(ElemLastTopVisibleEntry)) {
          ctxGroup.lastTopVisibleEntry = ReadUuid(xpp);
        } else if (name.equalsIgnoreCase(ElemGroup)) {
          ctxGroup = new PwGroupV4();
          ctxGroups.peek().AddGroup(ctxGroup, true);
          ctxGroups.push(ctxGroup);

          return SwitchContext(ctx, KdbContext.Group, xpp);
        } else if (name.equalsIgnoreCase(ElemEntry)) {
          ctxEntry = new PwEntryV4();
          ctxGroup.AddEntry(ctxEntry, true);

          entryInHistory = false;
          return SwitchContext(ctx, KdbContext.Entry, xpp);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case Entry:
        if (name.equalsIgnoreCase(ElemUuid)) {
          ctxEntry.setUUID(ReadUuid(xpp));
        } else if (name.equalsIgnoreCase(ElemIcon)) {
          ctxEntry.icon = db.iconFactory.getIcon((int) ReadUInt(xpp, 0));
        } else if (name.equalsIgnoreCase(ElemCustomIconID)) {
          ctxEntry.customIcon = db.iconFactory.getIcon(ReadUuid(xpp));
        } else if (name.equalsIgnoreCase(ElemFgColor)) {
          ctxEntry.foregroundColor = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemBgColor)) {
          ctxEntry.backgroupColor = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemOverrideUrl)) {
          ctxEntry.overrideURL = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemTags)) {
          ctxEntry.tags = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemTimes)) {
          return SwitchContext(ctx, KdbContext.EntryTimes, xpp);
        } else if (name.equalsIgnoreCase(ElemString)) {
          return SwitchContext(ctx, KdbContext.EntryString, xpp);
        } else if (name.equalsIgnoreCase(ElemBinary)) {
          return SwitchContext(ctx, KdbContext.EntryBinary, xpp);
        } else if (name.equalsIgnoreCase(ElemAutoType)) {
          return SwitchContext(ctx, KdbContext.EntryAutoType, xpp);
        } else if (name.equalsIgnoreCase(ElemHistory)) {
          assert (!entryInHistory);

          if (!entryInHistory) {
            ctxHistoryBase = ctxEntry;
            return SwitchContext(ctx, KdbContext.EntryHistory, xpp);
          } else {
            ReadUnknown(xpp);
          }
        } else {
          ReadUnknown(xpp);
        }
        break;

      case GroupTimes:
      case EntryTimes:
        ITimeLogger tl;
        if (ctx == KdbContext.GroupTimes) {
          tl = ctxGroup;
        } else {
          tl = ctxEntry;
        }

        if (name.equalsIgnoreCase(ElemLastModTime)) {
          tl.setLastModificationTime(ReadTime(xpp));
        } else if (name.equalsIgnoreCase(ElemCreationTime)) {
          tl.setCreationTime(ReadTime(xpp));
        } else if (name.equalsIgnoreCase(ElemLastAccessTime)) {
          tl.setLastAccessTime(ReadTime(xpp));
        } else if (name.equalsIgnoreCase(ElemExpiryTime)) {
          tl.setExpiryTime(ReadTime(xpp));
        } else if (name.equalsIgnoreCase(ElemExpires)) {
          tl.setExpires(ReadBool(xpp, false));
        } else if (name.equalsIgnoreCase(ElemUsageCount)) {
          tl.setUsageCount(ReadULong(xpp, 0));
        } else if (name.equalsIgnoreCase(ElemLocationChanged)) {
          tl.setLocationChanged(ReadTime(xpp));
        } else {
          ReadUnknown(xpp);
        }
        break;

      case EntryString:
        if (name.equalsIgnoreCase(ElemKey)) {
          ctxStringName = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemValue)) {
          ctxStringValue = ReadProtectedString(xpp);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case EntryBinary:
        if (name.equalsIgnoreCase(ElemKey)) {
          ctxBinaryName = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemValue)) {
          ctxBinaryValue = ReadProtectedBinary(xpp);
        }
        break;

      case EntryAutoType:
        if (name.equalsIgnoreCase(ElemAutoTypeEnabled)) {
          ctxEntry.autoType.enabled = ReadBool(xpp, true);
        } else if (name.equalsIgnoreCase(ElemAutoTypeObfuscation)) {
          ctxEntry.autoType.obfuscationOptions = ReadUInt(xpp, 0);
        } else if (name.equalsIgnoreCase(ElemAutoTypeDefaultSeq)) {
          ctxEntry.autoType.defaultSequence = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemAutoTypeItem)) {
          return SwitchContext(ctx, KdbContext.EntryAutoTypeItem, xpp);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case EntryAutoTypeItem:
        if (name.equalsIgnoreCase(ElemWindow)) {
          ctxATName = ReadString(xpp);
        } else if (name.equalsIgnoreCase(ElemKeystrokeSequence)) {
          ctxATSeq = ReadString(xpp);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case EntryHistory:
        if (name.equalsIgnoreCase(ElemEntry)) {
          ctxEntry = new PwEntryV4();
          ctxHistoryBase.history.add(ctxEntry);

          entryInHistory = true;
          return SwitchContext(ctx, KdbContext.Entry, xpp);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case RootDeletedObjects:
        if (name.equalsIgnoreCase(ElemDeletedObject)) {
          ctxDeletedObject = new PwDeletedObject();
          db.deletedObjects.add(ctxDeletedObject);

          return SwitchContext(ctx, KdbContext.DeletedObject, xpp);
        } else {
          ReadUnknown(xpp);
        }
        break;

      case DeletedObject:
        if (name.equalsIgnoreCase(ElemUuid)) {
          ctxDeletedObject.uuid = ReadUuid(xpp);
        } else if (name.equalsIgnoreCase(ElemDeletionTime)) {
          ctxDeletedObject.setDeletionTime(ReadTime(xpp));
        } else {
          ReadUnknown(xpp);
        }
        break;

      default:
        ReadUnknown(xpp);
        break;
    }

    return ctx;
  }