2017-11-06 5 views
0

저는 팀에서 API 자격 증명을 암호화하고 다른 팀/프로젝트로부터 암호화 된 메시지를받는 방법을 단순화하기 위해 암호화 라이브러리 작업을하고 있습니다. 지금은 우리의 AES에 적용하고있어 것을API/라이브러리에서 병렬 상속 계층 구조를 피하는 방법

public class KeyPair { 
    private final Key publicKey; 
    private final Key privateKey; 

    public Key getPublicKey() { 
     return publicKey; 
    } 

    public Key getPrivateKey() { 
     return privateKey; 
    } 
} 

public class RsaEncrypter implements Encrypter { 

    @Override 
    public Secret encrypt(Message message, Key publicKey) { 
     // Perform Encryption 
    } 
} 

public class RsaDecrypter implements Decrypter { 
    @Override 
    public String decrypt(Secret secret, Key privateKey) { 
     // Perform the decryption 
    } 
} 

그러나 :

public interface Key { 
    public byte[] getBytes(); 
} 

public interface Message { 
    public byte[] getBytes(); 
} 

public interface Secret { 
    public byte[] getBytes(); 
} 

public interface Decrypter { 
    public String decrypt(Secret secret, Key key); 
} 

public interface Encrypter { 
    public Secret encrypt(Message message, Key key); 
} 

이는 RSA 암호화를 포장 잘 작동 :

나는 도메인을 정의하기 위해이 최상위 인터페이스 시작 암호화 사용 사례 문제가 발생했습니다. CBC 모드에서 AES를 사용하기 때문에 Secret에는 InitializationVector가 포함되어 있습니다.

그래서 나는이있어 :

public class AesSecret implements Secret { 
    private byte[] cipherText; 
    private byte[] initilizationVector; 

    @Override 
    public byte[] getBytes() { 
     return cipherText; 
    } 

    public byte[] getInitilizationVector() { 
     return initilizationVector; 
    } 
} 

public class AesDecrypter implements Decrypter { 
    @Override 
    public String decrypt(Secret secret, Key key) { 
     try { 
      return decrypt((AesSecret) secret, key); 
     } catch (ClassCastException e) { 
      throw new IllegalArgumentException("AesDecrypter only supports subclasses of AesSecret", e); 
     } 
    } 

    public String decrypt(AesSecret secret, Key key) { 
     // Do the AES Decryption 
    } 
} 

ClassCastException이 나를 내가리스 코프 치환 원칙을 위반하고, 병렬 계층 코드 냄새를 도입하고있어라고 생각합니다. 방문자 패턴은이 코드 냄새에 대한 일반적인 해결책이라고 읽었지만 내 상황에 어떻게 적용되는지 알지 못했습니다.

제안 사항? 아니면 내가 이것을 과장 생각하고 있니?

은 내가 요점에이 클래스를 추가했습니다 : https://gist.github.com/mmeier/c493c28cbcd57a73d08419066cd23484

+1

Generics. '비밀'에'en/decrypter' 제네릭을 만드십시오. 생성하고'인터페이스'-'CbcSecret'은'extends Secret'을 추가하고 IV를 추가합니다. –

+0

또한,'getBytes'를 가진 모든 인터페이스는 어떤 부모를 위해 구걸하는 것처럼 보일 것입니다. 인터페이스에 대한'public' 메소드는 저를 슬프게 만듭니다. –

+1

마지막으로'Decrypter'가'Message'를 취하고 Encrypter가'String'을 반환한다는 것이 이상하게 보입니다. 나는 그들이 서로의 역일 것을 기대한다. –

답변

1

당신이 당신의 해독기는 일반적인 만들 수 있습니다. 이런 식으로 :

interface Decryptor<S extends Secret>{ 
    public String decrypt(S secret, Key publicKey); 
} 

그런 식으로 모든 구현은 Decryptor의 고유 한 비밀을 정의 할 수 있습니다. 그런 식으로 캐스팅을 제거 할 수 있습니다.

-1

암호 API에는 "일반적으로"init 함수가 있고 별도의 decryp/encrypt가 있습니다. API를 개발하는 경우 영감을 얻기 위해 다른 API를 연구하는 것이 좋습니다. Java에는 이미 사용할 수있는 Cipher API가 있습니다. 반면에 저는 암호를 쓰지 말고 대신 bouncycasle과 같은 라이브러리를 사용하는 것이 좋습니다.

+0

이 질문에 대답하지 않습니다. 그것은 코멘트에 속합니다. –

+0

맞아. – davidpetter

+0

내가 사용하는 구현은 BouncyCastle입니다. java.security와 BouncyCastle 모두 검사 된 예외의로드를 도입하기 때문에 자체 API 뒤에 숨어 있습니다. 그래서 저는 "under-the-hood"라이브러리를 사용하고 있습니다 만, 다른 이유로 들었을 때 너무 많은 지저분한 예외가있는 단순화 된 API를 공개하려고합니다. – gridDragon