001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2021, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.openid.connect.sdk.assurance.evidences.attachment; 019 020 021import java.security.MessageDigest; 022import java.security.NoSuchAlgorithmException; 023import java.util.Objects; 024 025import net.jcip.annotations.Immutable; 026import net.minidev.json.JSONObject; 027 028import com.nimbusds.jose.util.Base64; 029import com.nimbusds.oauth2.sdk.ParseException; 030import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 031 032 033/** 034 * Cryptographic digest. 035 * 036 * <p>Related specifications: 037 * 038 * <ul> 039 * <li>OpenID Connect for Identity Assurance 1.0, section 5.1.2.2. 040 * </ul> 041 */ 042@Immutable 043public final class Digest { 044 045 046 /** 047 * The hash algorithm. 048 */ 049 private final HashAlgorithm alg; 050 051 052 /** 053 * The hash value. 054 */ 055 private final Base64 value; 056 057 058 /** 059 * Creates a new cryptographic digest. 060 * 061 * @param alg The hash algorithm. Must not be {@code null}. 062 * @param value The hash value. Must not be {@code null}. 063 */ 064 public Digest(final HashAlgorithm alg, final Base64 value) { 065 Objects.requireNonNull(alg); 066 this.alg = alg; 067 Objects.requireNonNull(value); 068 this.value = value; 069 } 070 071 072 /** 073 * Returns the hash algorithm. 074 * 075 * @return The hash algorithm. 076 */ 077 public HashAlgorithm getHashAlgorithm() { 078 return alg; 079 } 080 081 082 /** 083 * Returns the hash value. 084 * 085 * @return the hash value. 086 */ 087 public Base64 getValue() { 088 return value; 089 } 090 091 092 /** 093 * Returns {@code true} if this digest matches the computed for the 094 * specified content. 095 * 096 * @param content The content. Must not be {@code null}. 097 * 098 * @return If {@code true} if the digest matches the content, else 099 * {@code false}. 100 * 101 * @throws NoSuchAlgorithmException If the hash algorithm isn't 102 * supported. 103 */ 104 public boolean matches(final Base64 content) 105 throws NoSuchAlgorithmException { 106 107 Digest computed = Digest.compute(getHashAlgorithm(), content); 108 return this.equals(computed); 109 } 110 111 112 /** 113 * Returns a JSON object representation of this cryptographic digest. 114 * 115 * @return The JSON object. 116 */ 117 public JSONObject toJSONObject() { 118 JSONObject jsonObject = new JSONObject(); 119 jsonObject.put("alg", getHashAlgorithm().getValue()); 120 jsonObject.put("value", getValue().toString()); 121 return jsonObject; 122 } 123 124 125 @Override 126 public boolean equals(Object o) { 127 if (this == o) return true; 128 if (!(o instanceof Digest)) return false; 129 Digest digest = (Digest) o; 130 return alg.equals(digest.alg) && getValue().equals(digest.getValue()); 131 } 132 133 134 @Override 135 public int hashCode() { 136 return Objects.hash(alg, getValue()); 137 } 138 139 140 /** 141 * Computes the digest for the specified content. 142 * 143 * @param alg The hash algorithm. Must not be {@code null}. 144 * @param content The content. Must not be {@code null}. 145 * 146 * @return The digest. 147 * 148 * @throws NoSuchAlgorithmException If the hash algorithm isn't 149 * supported. 150 */ 151 public static Digest compute(final HashAlgorithm alg, final Base64 content) 152 throws NoSuchAlgorithmException { 153 154 return compute(alg, content.decode()); 155 } 156 157 158 /** 159 * Computes the digest for the specified content. 160 * 161 * @param alg The hash algorithm. Must not be {@code null}. 162 * @param content The content. Must not be {@code null}. 163 * 164 * @return The digest. 165 * 166 * @throws NoSuchAlgorithmException If the hash algorithm isn't 167 * supported. 168 */ 169 public static Digest compute(final HashAlgorithm alg, final byte[] content) 170 throws NoSuchAlgorithmException { 171 172 MessageDigest md = MessageDigest.getInstance(alg.getValue().toUpperCase()); 173 byte[] hash = md.digest(content); 174 return new Digest(alg, Base64.encode(hash)); 175 } 176 177 178 /** 179 * Parses a digest from the specified JSON object. 180 * 181 * @param jsonObject The JSON object. 182 * 183 * @return The cryptographic digest. 184 * 185 * @throws ParseException If parsing failed. 186 */ 187 public static Digest parse(final JSONObject jsonObject) 188 throws ParseException { 189 190 HashAlgorithm alg = new HashAlgorithm(JSONObjectUtils.getString(jsonObject, "alg")); 191 Base64 value = new Base64(JSONObjectUtils.getString(jsonObject, "value")); 192 return new Digest(alg, value); 193 } 194}