001 package org.cumulus4j.store.model; 002 003 import javax.jdo.PersistenceManager; 004 import javax.jdo.annotations.IdGeneratorStrategy; 005 import javax.jdo.annotations.IdentityType; 006 import javax.jdo.annotations.NullValue; 007 import javax.jdo.annotations.PersistenceCapable; 008 import javax.jdo.annotations.Persistent; 009 import javax.jdo.annotations.PrimaryKey; 010 import javax.jdo.annotations.Queries; 011 import javax.jdo.annotations.Query; 012 import javax.jdo.annotations.Sequence; 013 import javax.jdo.annotations.SequenceStrategy; 014 import javax.jdo.annotations.Unique; 015 import javax.jdo.annotations.Version; 016 import javax.jdo.annotations.VersionStrategy; 017 018 import org.cumulus4j.crypto.Cipher; 019 import org.cumulus4j.crypto.CryptoRegistry; 020 import org.cumulus4j.store.EncryptionCoordinateSetManager; 021 import org.cumulus4j.store.crypto.CryptoManager; 022 import org.cumulus4j.store.crypto.CryptoSession; 023 024 /** 025 * <p> 026 * Encryption coordinates used to encrypt a persistent record. 027 * </p> 028 * <p> 029 * Via the {@link EncryptionCoordinateSetManager}, the {@link CryptoManager} 030 * (or {@link CryptoSession}) implementation can map the {@link Cipher#getTransformation() 031 * cipher-transformation} and other encryption-coordinates (e.g. the {@link #getMACAlgorithm() MAC algorithm}) 032 * to a number in order to save space in each persistent record. 033 * </p> 034 * 035 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de 036 */ 037 @PersistenceCapable(identityType=IdentityType.APPLICATION, detachable="true") 038 @Version(strategy=VersionStrategy.VERSION_NUMBER) 039 @Unique(name="EncryptionCoordinateSet_allAlgorithms", members={"cipherTransformation", "macAlgorithm"}) 040 @Queries({ 041 @Query( 042 name="getEncryptionCoordinateSetByAllAlgorithms", 043 value="SELECT UNIQUE WHERE this.cipherTransformation == :cipherTransformation && this.macAlgorithm == :macAlgorithm" 044 ) 045 }) 046 @Sequence(name="EncryptionCoordinateSetSequence", datastoreSequence="EncryptionCoordinateSetSequence", initialValue=0, strategy=SequenceStrategy.CONTIGUOUS) 047 public class EncryptionCoordinateSet 048 { 049 /** 050 * <p> 051 * Constant for deactivating the <a target="_blank" href="http://en.wikipedia.org/wiki/Message_authentication_code">MAC</a>. 052 * </p> 053 * <p> 054 * <b>Important: Deactivating the MAC is dangerous!</b> Choose this value only, if you are absolutely 055 * sure that your {@link #getCipherTransformation() cipher-transformation} already 056 * provides authentication - like <a target="_blank" href="http://en.wikipedia.org/wiki/Galois/Counter_Mode">GCM</a> 057 * does for example. 058 * </p> 059 */ 060 public static final String MAC_ALGORITHM_NONE = "NONE"; 061 062 @PrimaryKey 063 @Persistent(valueStrategy=IdGeneratorStrategy.NATIVE, sequence="EncryptionCoordinateSetSequence") 064 private int encryptionCoordinateSetID = -1; 065 066 @Persistent(nullValue=NullValue.EXCEPTION) 067 private String cipherTransformation; 068 069 @Persistent(nullValue=NullValue.EXCEPTION) 070 private String macAlgorithm; 071 072 /** 073 * Create a new <code>EncryptionCoordinateSet</code>. This default constructor only exists 074 * for JDO and should never be used directly! 075 */ 076 protected EncryptionCoordinateSet() { } 077 078 /** 079 * Create a new <code>EncryptionCoordinateSet</code>. Instead of using this constructor, 080 * you should use {@link #createEncryptionCoordinateSet(PersistenceManager, String, String)}! 081 * 082 * @param cipherTransformation the cipher-transformation. 083 * @param macAlgorithm the MAC-algorithm. 084 */ 085 protected EncryptionCoordinateSet(String cipherTransformation, String macAlgorithm) 086 { 087 if (cipherTransformation == null) 088 throw new IllegalArgumentException("cipherTransformation == null"); 089 090 if (macAlgorithm == null) 091 throw new IllegalArgumentException("macAlgorithm == null"); 092 093 this.cipherTransformation = cipherTransformation; 094 this.macAlgorithm = macAlgorithm; 095 } 096 097 /** 098 * <p> 099 * Get the unique numeric identifier of this <code>EncryptionCoordinateSet</code>. 100 * </p> 101 * <p> 102 * Note: Implementors of {@link CryptoManager} (or {@link CryptoSession} respectively) might 103 * choose not to store the entire int value (4 bytes), but reduce the size. Every time the 104 * encryption configuration is changed, a new instance of this class is persisted. Restricting 105 * the size to 2 bytes, for example, still gives the administrator the possibility to change 106 * the configuration 65535 times - which is likely enough. 107 * </p> 108 * 109 * @return the unique numeric identifier (primary key). 110 */ 111 public int getEncryptionCoordinateSetID() { 112 return encryptionCoordinateSetID; 113 } 114 115 /** 116 * Get the {@link Cipher#getTransformation() cipher-transformation} that identifies the encryption 117 * algorithm, the mode and the padding used to encrypt a record. The system usually passes 118 * this value to {@link CryptoRegistry#createCipher(String)}. 119 * @return the {@link Cipher#getTransformation() cipher-transformation}. Never <code>null</code>. 120 */ 121 public String getCipherTransformation() { 122 return cipherTransformation; 123 } 124 /** 125 * <p> 126 * Get the <a target="_blank" href="http://en.wikipedia.org/wiki/Message_authentication_code">MAC</a>-algorithm 127 * used to protect a record against corruption/manipulation. 128 * </p> 129 * <p> 130 * Implementors of {@link CryptoManager}/{@link CryptoSession} should take {@link #MAC_ALGORITHM_NONE} 131 * into account! If this value equals that constant, MAC calculation and storage should be skipped. 132 * </p> 133 * @return the <a target="_blank" href="http://en.wikipedia.org/wiki/Message_authentication_code">MAC</a>-algorithm. 134 */ 135 public String getMACAlgorithm() { 136 return macAlgorithm; 137 } 138 }