键和参数对象

在实践中,Tink 提供了 Key 对象来表示,同时提供了 Parameters 对象来表示 Parameters。例如,在 Java 中,我们使用 AesGcmKey 对象来表示 AES GCM 密钥。

在本部分中,我们将介绍如何在 Java 中设计这些对象以及它们如何交互。

Parameters 个对象

考虑 AES GCM,这是一种广泛使用的 AEAD 加密方案。 Tink 可为 AesGcmParameters 对象提供创建 AesGcmKey 所需的必要信息,我们稍后会对此进行说明。Java 中的参数层次结构如下所示:

public abstract class Parameters {
  public abstract boolean hasIdRequirement();
}

public abstract class AeadParameters extends Parameters {}

public final class AesGcmParameters extends AeadParameters {
  /**
   * The Variant specified how ciphertexts are [tagged](/tink/design/keysets#tagging_ciphertexts).
   */
  public static final class Variant {...}
  /** A helper object to create new AesGcmParameters. */
  public static final class Builder {...}

  public int getKeySizeBytes() {...}
  public int getIvSizeBytes() {...}
  public int getTagSizeBytes() {...}

  public Variant getVariant() {...}

  public OutputPrefixType getOutputPrefixType() {...}
  public boolean equals(Object object) {...}
  public int hashCode() {...}
}

密钥集、标记密文部分中所述,某些密钥在密钥集中时对其 ID 有要求。每个 Parameters 对象都有一个 hasIdRequirement 方法,用于指定由此 Parameters 对象创建的键是否具有此类必需的 ID。

接下来,AesGcmParameters 对象提供了 getKeySizeBytes()getIvSizeBytes()getTagSizeBytes() 方法。这些命令会返回所用密钥的长度、所用 IV 的长度以及生成的标记的长度(以字节为单位)。虽然 Tink 提供其中一些函数是为了提供完整性,但它并不总是允许为每个选项创建 Aead。例如,AES GCM 目前仅支持 12 字节 IV。

AesGcmParameters 对象还会替换之前定义的方法(以及 Java 标准方法 equalshashCode,这被视为一种好的做法)。

最后,它提供用于创建新的 AeadParameters 对象的静态方法。这些测试会验证输入,即检查大小是 16、24 或 32 之一。

关键对象

Tink 还有一个密钥层次结构。我们的 AES GCM 示例仍如下所示:

public abstract class Key {
  public abstract Parameters getParameters();
  public abstract @Nullable Integer getIdRequirementOrNull();
  public abstract boolean equalsKey(Key other);
}

public abstract class AeadKey extends Key {
  public abstract AeadParameters getParameters();
  public abstract Bytes getOutputPrefix();
}

public final class AesGcmKey implements AeadKey {
  public SecretBytes getKeyBytes();
  public abstract Bytes getOutputPrefix();
  public AesGcmParameters getParameters();
  public @Nullable Integer getIdRequirementOrNull();
  public boolean equalsKey(Key object);
}

getIdRequirementOrNull 方法会返回此键需要具有的 ID,如果没有要求,则返回 null。(之所以对密钥提出这样的要求,是因为 Tink 在某些情况下会在密文或签名前添加字符串 0x01<id> 作为前缀,请参阅密文标记部分)。

这始终与 getParameters().hasIdRequirement() 的结果一致,并且新键类的实现者需要确保这一点。

Key 的实现还需要提供 equalsKey 方法,以比较不同的键。这种方法通常很有用:例如,在测试密钥派生时,人们有意确保重复应用派生可产生相同的密钥对象。此外,KMS 可能想要检查它为不同用户提供的任何密钥是否相等(当用户共享密钥并多次将其上传到同一 KMS 时,就会发生这种情况)。值得注意的是,我们没有替换 Java 方法 equals,因为这需要替换 hashCode。如果不做出未经证实的假设,就没有办法以与 equals 兼容的安全方式实现 hashCode

接下来,我们需要 getParameters() 方法。这样,用户就可以获取有关用于创建密钥的参数的原始信息。

最后,AesGcmKey 具有一个 getKeyBytes 方法,该方法会返回原始密钥材料。这些方法对于密钥类非常典型:它们特定于相应类型,并提供对底层密钥材料的访问。通过使用这些基元,用户原则上可以实现多种目的,例如实现由密钥表示的基元,或序列化密钥以将其存储在磁盘上或通过网络发送。密钥本身负责保护密钥材料免遭未经授权的访问。例如,SecretBytes 需要访问令牌才能提供资料(请参阅访问权限控制)。

非对称密钥

对于非对称基元,Tink 使用了两个 Key 类,一个用于私钥,另一个用于公钥。对于参数,使用同一类更方便(因为只有一个类可用于生成键)。

Tink 还有一个具有额外函数 getPublicKey() 的接口 PrivateKey