001package com.nimbusds.openid.connect.sdk.id; 002 003 004import java.nio.charset.Charset; 005import java.security.MessageDigest; 006import java.security.NoSuchAlgorithmException; 007 008import org.apache.commons.codec.binary.Base64; 009 010import com.nimbusds.oauth2.sdk.id.Subject; 011 012 013/** 014 * SHA-256 based generator of pairwise subject identifiers. 015 * 016 * <p>Algorithm: 017 * 018 * <pre> 019 * sub = SHA-256 ( sector_identifier | local_account_id | salt ) 020 * </pre> 021 * 022 * <p>Related specifications: 023 * 024 * <ul> 025 * <li>OpenID Connect Core 1.0, section 8.1. 026 * </ul> 027 */ 028public class HashingSubjectIdentifierGenerator extends PairwiseSubjectIdentifierGenerator { 029 030 031 /** 032 * The hashing algorithm. 033 */ 034 public static final String HASH_ALGORITHM = "SHA-256"; 035 036 037 /** 038 * UTF-8 is the charset for byte to and from string conversions. 039 */ 040 private final Charset charset; 041 042 043 /** 044 * The salt. 045 */ 046 private final byte[] salt; 047 048 049 /** 050 * Creates a new SHA-256 based generator of pairwise subject 051 * identifiers. 052 * 053 * @param salt The string to use for the salt. Must not be empty, blank 054 * or {@code null}. 055 * 056 * @throws NoSuchAlgorithmException If SHA-256 isn't supported by the 057 * underlying JVM. 058 */ 059 public HashingSubjectIdentifierGenerator(final String salt) 060 throws NoSuchAlgorithmException { 061 062 charset = Charset.forName("UTF-8"); 063 064 if (salt == null) 065 throw new IllegalArgumentException("The salt must not be null"); 066 067 if (salt.trim().isEmpty()) 068 throw new IllegalArgumentException("The salt string must not be blank or empty"); 069 070 this.salt = salt.getBytes(charset); 071 072 MessageDigest.getInstance(HASH_ALGORITHM); 073 } 074 075 076 /** 077 * Returns the salt bytes. 078 * 079 * @return The salt bytes. 080 */ 081 public byte[] saltBytes() { 082 083 return salt; 084 } 085 086 087 @Override 088 public Subject generate(final String sectorIdentifier, final Subject localSub) { 089 090 MessageDigest sha256; 091 092 try { 093 sha256 = MessageDigest.getInstance(HASH_ALGORITHM); 094 095 } catch (NoSuchAlgorithmException e) { 096 097 throw new IllegalStateException(e.getMessage(), e); 098 } 099 100 sha256.update(sectorIdentifier.getBytes(charset)); 101 sha256.update(localSub.getValue().getBytes(charset)); 102 byte[] hash = sha256.digest(salt); 103 104 return new Subject(Base64.encodeBase64URLSafeString(hash)); 105 } 106}