728x90

Too many open files 해결하기

출처 : http://blog.leekyoungil.com/?p=219

IO 관련해서 개발을 하다보면 자주 마주치는 부분중 하나가 이 오류일 것이다. 

java.io.IOException: Too many open files

일단 해당 메시지로 구글 검색을 하면 대부분 해결책이 

“시스템의 open files 를 올려라 리눅스의 경우 ulimit -n 65535” 이정도 및 limit.conf 파일 수정 하는 것이
나오는 것이 대부분 일것이다. 

하지만 그전에 프로그램에서 뭔가 파일을 열고 닫는 부분에서 버그가 있어야 하지 않을까? 라는 것으로 접근하는 것이
가장 우선시 되어야 할 사항 이라고 생각한다. 

일단 이렇게 접근 하기 위해서는 프로그램이 실행이 될때 (어떠한 액션이 발생할때) 지금 열린 파일의 갯수를 알아야 할것이 아닌가? 

os 가 linux 라고 가정 할때 대상 프로세스에서 열린 파일의 수를 실시간으로 확인이 가능한 간단한 스크립트를 소개하겠다.

가령 대상 프로세스가 java 프로세스라고 가정하면 

shell # ps aux | grep java

해당 프로세스 리스트를 확인하면 

아래와 같이 593228 라는 프로세스 아이디가 나온다.

그러면 아래처럼 linux shell 상에서 명령어를 실행하면…

라고 실행하면 2초 단위로 해당 프로세스에서 열린 파일의 갯수가 출력되니 디버깅에 참고하기 바란다.


반응형
728x90

출처 : http://zero-gravity.tistory.com/221

OTP 기능을 구현하라는 미션이 떨어졌고, 힌트로는 구글OTP라는 것이 있다라는 것만 받았다.


   찾아보니 거의 다 "Google Authenticator"라는 앱을 다운받아서 구글 로그인을 할 때에 이용하는 내용이었다.


   뭔가 구글에서 제공하는 API가 있어야 구글앱을 이용해서 개발을 할 수 있을 텐데, 눈을 씻고 찾아봐도 API는 없었다.


   찾다찾다 구글앱의 공식 홈페이지에서 파일들을 다운로드 할 수 있는 곳을 찾았는데, C언어로 되어있고 내가 원하는 것은 아니었다. 아마도 SSH로 접속해서 이걸 설치하고 로그인을 할 때에 사용하는 그런 종류인 듯 싶다.(이곳 참고)


   알고리즘을 중심으로 찾아본 결과, 아마도 IETF에 있는 RFC6238이라는 문서를 기반으로 구글앱이 이와 같은 알고리즘으로 구현을 해놓은 것 같다.


   따져보니 이것과 똑같은 알고리즘으로 Key/바코드를 만들어내고 그것을 검증하는 코드를 짜면 완벽하게 구글앱을 사용하는 OTP 기능을 만들어낼 수 있을 것 같았다.


   다른 사람들이 만들어놓은 자바 코드를 찾지 못했을 경우, 최악의 경우엔 정말 그렇게 해보려고 했다.


   국내에선 파이썬 코드를 쉽게 찾을 수 있었지만 자바가 아니어서 아무 쓸모가 없었다.


   지푸라기라도 잡는 심정으로 온갖 검색어 조합을 동원하여 외국 사이트를 이 잡듯이 뒤진 결과,


   다행히 누군가 자바스크립트로 구현해놓은 코드를 발견했다.


   미칠듯이 기뻤다. 속으로 감동의 눈물을 흘릴 정도였다. 그러나 의존하는 라이브러리 파일들을 제대로 다 링크해주고, 코드도 이대로 했음에도 불구하고 어떤 연유에서인지 내가 테스트하는 프로젝트에서는 작동하지 않았다. 


   이내 포기하고 다른 코드를 찾아 헤맸는데, 정말 다행스럽게도 자바로 구현한 코드를 찾았냈다!!!


   그런데 이것도 코드에서 sercretSize, numOfScratchCodes, scratchCodeSize를 몇으로 설정해줘야 하는지 별 말도 없고 그닥 친절하지 않아서 적용에 실패했다.


   더 찾아보니 이 코드를 기반으로 복잡하게 만들어놓은 코드를 발견했는데, 이건 더 머리가 터질 것 같았다. 하루 반 동안 붙잡고 하다가 GG.


   결국 다시 간단한 자바 코드로 돌아가서 붙잡고 요리조리 해본 결과, 성공!!!!


   서론이 길었다.;;


   아무튼 총 4일 동안 끙끙대서 성공한 결과물을 아래에 설명하고자 한다. 비록 내가 처음부터 날코딩한 것은 아니지만, OTP를 구현하려 나처럼 인터넷 망망대해를 떠돌고 있을 불쌍한 중생들을 위해 올려놓는다.




   먼저 OTP란 무엇이고 어떻게 돌아가는지부터 알고 들어가야 하니 간단하게 짚고 넘어가겠다.



   1. OTP란?


   One Time Password의 약자로, 우리말로 하면 일회용 비밀번호라 할 수 있다. 일회성이라는 특징 때문에 일반 비밀번호 입력이나 공인인증서 이용보다도 더 안전한 방법으로 알려져있다. 주로 금융권이나 일반 웹사이트 2차 로그인 인증으로 많이 활용되고 있다. OTP의 종류에는 원리에 따라 S/KEY방식, 시간 동기화 방식, 챌린지 응답 방식, 이벤트 동기화 방식 등이 있다. (좀더 자세한 내용을 알고 싶다면, 위키백과 참조) 여기서는 이중 시간 동기화 방식을 사용한 Google Authenticator라는 앱으로 TOTP 인증을 구현해보도록 하겠다.




   2. TOTP((Time-based One Time Password)의 원리


   많은 사람들이 오해하는 게 있는데(나 또한 그랬다), OTP 기기와 서버가 통신하는 줄 착각한다. 실상은 그렇지 않다. OTP 기기와 서버는 모두 같은 알고리즘을 바탕으로 하기 때문에 통신이 필요치 않다. 원리는 간단하다. 서버쪽에서 해당 알고리즘으로 Key나 바코드 주소를 생성해주면 그걸 OTP 기기에 입력해준다. 그러면 기기에서는 그 Key나 바코드를 기준으로 하여 30~60초 마다 계속하여 새로운 일회용 비밀번호를 생성해낸다. 그 일회용 비밀번호를 입력하여 서버로 전송하면 서버에서 그 비밀번호가 맞는지 알고리즘으로 확인하는 방식이다. 여기서 구글앱을 이용한다는 것은 OTP 기기 대신에 스마트폰에 있는 Google Authenticator라는 앱으로 대체한다는 것이다.


   뭔가 복잡해보이지만, 이해하고나면 쉽다.




   3. Java로 구현해보기.


   자 그럼 Java로 직접해보자. 아래는 JSP를 이용해서 웹사이트에 구현하다는 가정 하에 진행하였다.


   먼저 commons-codec.jar 파일을 라이브러리에 추가해준다.



 commons-codec-1.9.jar



   또 만약 자바 버전이 1.6 이하일 경우에는 아래의 파일을 다운받아서 라이브러리 추가해준다.



 security.jar



   그리고 자신의 스마트폰에 Google Authenticator 앱을 다운받아 설치해놓는다.

   


   다음은 실제 코드다.


   2차 인증 로그인 리퀘스트가 들어올 시, 사용자명과 계정명을 받아서 키를 생성할 부분.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.commons.codec.binary.Base32;
 
public class OtpServlet extends HttpServlet {
 
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, IOException {
         
        // Allocating the buffer
//      byte[] buffer = new byte[secretSize + numOfScratchCodes * scratchCodeSize];
        byte[] buffer = new byte[5 5 5];
         
        // Filling the buffer with random numbers.
        // Notice: you want to reuse the same random generator
        // while generating larger random number sequences.
        new Random().nextBytes(buffer);
 
        // Getting the key and converting it to Base32
        Base32 codec = new Base32();
//      byte[] secretKey = Arrays.copyOf(buffer, secretSize);
        byte[] secretKey = Arrays.copyOf(buffer, 5);
        byte[] bEncodedKey = codec.encode(secretKey);
         
        // 생성된 Key!
        String encodedKey = new String(bEncodedKey);
         
        System.out.println("encodedKey : " + encodedKey);
         
//      String url = getQRBarcodeURL(userName, hostName, secretKeyStr);
        // userName과 hostName은 변수로 받아서 넣어야 하지만, 여기선 테스트를 위해 하드코딩 해줬다.
        String url = getQRBarcodeURL("hj""company.com", encodedKey); // 생성된 바코드 주소!
        System.out.println("URL : " + url);
         
        String view = "/WEB-INF/view/otpTest.jsp";
         
        req.setAttribute("encodedKey", encodedKey);
        req.setAttribute("url", url);
         
        req.getRequestDispatcher(view).forward(req, res);
         
    }
     
    public static String getQRBarcodeURL(String user, String host, String secret) {
         
        return String.format(format, user, host, secret);
    }
     
}




   otpTest.jsp

1
2
3
4
5
6
7
8
9
10
당신의 키는 → ${encodedKey } 입니다. <br>
당신의 바코드 주소는 → ${url } 입니다. <br><br>
 
<form action="<%=request.getContextPath() %>/otpTestResult.ok" method="get">
    code : <input type="text" name="user_code"><br><br>
     
    <input type="hidden" name="encodedKey" value="${encodedKey }" readonly="readonly"><br><br>
    <input type="submit" value="전송!">
     
</form>


   키나 바코드를 이용해 구글앱에서 항목을 추가한 뒤, 거기서 생성되는 일회용 비밀번호를 code 부분에 써주고 전송을 클릭한다.



   code 부분에 저 숫자를 넣어주면 된다.




   전송 리퀘스트를 받는 부분에서 해당 코드가 맞는지 여부를 검사한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
 
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.commons.codec.binary.Base32;
 
public class OtpResultServlet extends HttpServlet {
 
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, IOException {
         
        String user_codeStr = req.getParameter("user_code");
        long user_code = Integer.parseInt(user_codeStr);
        String encodedKey = req.getParameter("encodedKey");
        long l = new Date().getTime();
        long ll =  l / 30000;
         
        boolean check_code = false;
        try {
            // 키, 코드, 시간으로 일회용 비밀번호가 맞는지 일치 여부 확인.
            check_code = check_code(encodedKey, user_code, ll);
        catch (InvalidKeyException e) {
            e.printStackTrace();
        catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
         
        // 일치한다면 true.
        System.out.println("check_code : " + check_code);
         
    }
 
    private static boolean check_code(String secret, long code, long t) throwsNoSuchAlgorithmException, InvalidKeyException {
        Base32 codec = new Base32();
        byte[] decodedKey = codec.decode(secret);
 
        // Window is used to check codes generated in the near past.
        // You can use this value to tune how far you're willing to go.
        int window = 3;
        for (int i = -window; i <= window; ++i) {
            long hash = verify_code(decodedKey, t + i);
 
            if (hash == code) {
                return true;
            }
        }
 
        // The validation code is invalid.
        return false;
    }
     
    private static int verify_code(byte[] key, long t)
            throws NoSuchAlgorithmException, InvalidKeyException {
        byte[] data = new byte[8];
        long value = t;
        for (int i = 8; i-- > 0; value >>>= 8) {
            data[i] = (byte) value;
        }
 
        SecretKeySpec signKey = new SecretKeySpec(key, "HmacSHA1");
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(signKey);
        byte[] hash = mac.doFinal(data);
 
        int offset = hash[20 1] & 0xF;
 
        // We're using a long because Java hasn't got unsigned int.
        long truncatedHash = 0;
        for (int i = 0; i < 4; ++i) {
            truncatedHash <<= 8;
            // We are dealing with signed bytes:
            // we just keep the first byte.
            truncatedHash |= (hash[offset + i] & 0xFF);
        }
 
        truncatedHash &= 0x7FFFFFFF;
        truncatedHash %= 1000000;
 
        return (int) truncatedHash;
    }
     
}


   시간이 흘러서 일회용 비밀번호가 계속 바뀌어도 바뀐 일회용 비밀번호를 입력하면 완벽하게 true를 뱉어냄을 확인할 수 있다.


   지금까지 구글앱을 이용한 OTP 기능을 어떻게 구현하는지 알아봤다.


   사실 구글앱을 이용하는 방법 말고도 오픈소스를 이용한다든지, 돈으로 떼우는 방법 등등..  방법은 많다.


   아무쪼록 구글앱을 이용한 OTP 기능 개발을 찾아헤매는 사람들에게 도움이 되었길 바란다.

반응형
728x90

INFORMATIONAL
Errata Exist

Internet Engineering Task Force (IETF)                        D. M'Raihi
Request for Comments: 6238                                Verisign, Inc.
Category: Informational                                       S. Machani
ISSN: 2070-1721                                         Diversinet Corp.
                                                                  M. Pei
                                                                Symantec
                                                               J. Rydell
                                                          Portwise, Inc.
                                                                May 2011


              

TOTP: Time-Based One-Time Password Algorithm

Abstract This document describes an extension of the One-Time Password (OTP) algorithm, namely the HMAC-based One-Time Password (HOTP) algorithm, as defined in RFC 4226, to support the time-based moving factor. The HOTP algorithm specifies an event-based OTP algorithm, where the moving factor is an event counter. The present work bases the moving factor on a time value. A time-based variant of the OTP algorithm provides short-lived OTP values, which are desirable for enhanced security. The proposed algorithm can be used across a wide range of network applications, from remote Virtual Private Network (VPN) access and Wi-Fi network logon to transaction-oriented Web applications. The authors believe that a common and shared algorithm will facilitate adoption of two-factor authentication on the Internet by enabling interoperability across commercial and open-source implementations. Status of This Memo This document is not an Internet Standards Track specification; it is published for informational purposes. This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Not all documents approved by the IESG are a candidate for any level of Internet Standard; see Section 2 of RFC 5741. Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at http://www.rfc-editor.org/info/rfc6238. M'Raihi, et al. Informational [Page 1]


RFC 6238                      HOTPTimeBased                     May 2011


Copyright Notice

   Copyright (c) 2011 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents
   (http://trustee.ietf.org/license-info) in effect on the date of
   publication of this document.  Please review these documents
   carefully, as they describe your rights and restrictions with respect
   to this document.  Code Components extracted from this document must
   include Simplified BSD License text as described in Section 4.e of
   the Trust Legal Provisions and are provided without warranty as
   described in the Simplified BSD License.

Table of Contents

   1. Introduction ....................................................2
      1.1. Scope ......................................................2
      1.2. Background .................................................3
   2. Notation and Terminology ........................................3
   3. Algorithm Requirements ..........................................3
   4. TOTP Algorithm ..................................................4
      4.1. Notations ..................................................4
      4.2. Description ................................................4
   5. Security Considerations .........................................5
      5.1. General ....................................................5
      5.2. Validation and Time-Step Size ..............................6
   6. Resynchronization ...............................................7
   7. Acknowledgements ................................................7
   8. References ......................................................8
      8.1. Normative References .......................................8
      8.2. Informative References .....................................8
   Appendix A. TOTP Algorithm: Reference Implementation ...............9
   Appendix B. Test Vectors ..........................................14

1. Introduction

1.1. Scope

This document describes an extension of the One-Time Password (OTP) algorithm, namely the HMAC-based One-Time Password (HOTP) algorithm, as defined in [RFC4226], to support the time-based moving factor. M'Raihi, et al. Informational [Page 2]


RFC 6238                      HOTPTimeBased                     May 2011


1.2. Background

As defined in [RFC4226], the HOTP algorithm is based on the HMAC-SHA-1 algorithm (as specified in [RFC2104]) and applied to an increasing counter value representing the message in the HMAC computation. Basically, the output of the HMAC-SHA-1 calculation is truncated to obtain user-friendly values: HOTP(K,C) = Truncate(HMAC-SHA-1(K,C)) where Truncate represents the function that can convert an HMAC-SHA-1 value into an HOTP value. K and C represent the shared secret and counter value; see [RFC4226] for detailed definitions. TOTP is the time-based variant of this algorithm, where a value T, derived from a time reference and a time step, replaces the counter C in the HOTP computation. TOTP implementations MAY use HMAC-SHA-256 or HMAC-SHA-512 functions, based on SHA-256 or SHA-512 [SHA2] hash functions, instead of the HMAC-SHA-1 function that has been specified for the HOTP computation in [RFC4226].

2. Notation and Terminology

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].

3. Algorithm Requirements

This section summarizes the requirements taken into account for designing the TOTP algorithm. R1: The prover (e.g., token, soft token) and verifier (authentication or validation server) MUST know or be able to derive the current Unix time (i.e., the number of seconds elapsed since midnight UTC of January 1, 1970) for OTP generation. See [UT] for a more detailed definition of the commonly known "Unix time". The precision of the time used by the prover affects how often the clock synchronization should be done; see Section 6. R2: The prover and verifier MUST either share the same secret or the knowledge of a secret transformation to generate a shared secret. R3: The algorithm MUST use HOTP [RFC4226] as a key building block. M'Raihi, et al. Informational [Page 3]


RFC 6238                      HOTPTimeBased                     May 2011


   R4: The prover and verifier MUST use the same time-step value X.

   R5: There MUST be a unique secret (key) for each prover.

   R6: The keys SHOULD be randomly generated or derived using key
       derivation algorithms.

   R7: The keys MAY be stored in a tamper-resistant device and SHOULD be
       protected against unauthorized access and usage.

4. TOTP Algorithm

This variant of the HOTP algorithm specifies the calculation of a one-time password value, based on a representation of the counter as a time factor.

4.1. Notations

o X represents the time step in seconds (default value X = 30 seconds) and is a system parameter. o T0 is the Unix time to start counting time steps (default value is 0, i.e., the Unix epoch) and is also a system parameter.

4.2. Description

Basically, we define TOTP as TOTP = HOTP(K, T), where T is an integer and represents the number of time steps between the initial counter time T0 and the current Unix time. More specifically, T = (Current Unix time - T0) / X, where the default floor function is used in the computation. For example, with T0 = 0 and Time Step X = 30, T = 1 if the current Unix time is 59 seconds, and T = 2 if the current Unix time is 60 seconds. The implementation of this algorithm MUST support a time value T larger than a 32-bit integer when it is beyond the year 2038. The value of the system parameters X and T0 are pre-established during the provisioning process and communicated between a prover and verifier as part of the provisioning step. The provisioning flow is out of scope of this document; refer to [RFC6030] for such provisioning container specifications. M'Raihi, et al. Informational [Page 4]


RFC 6238                      HOTPTimeBased                     May 2011


5. Security Considerations

5.1. General

The security and strength of this algorithm depend on the properties of the underlying building block HOTP, which is a construction based on HMAC [RFC2104] using SHA-1 as the hash function. The conclusion of the security analysis detailed in [RFC4226] is that, for all practical purposes, the outputs of the dynamic truncation on distinct inputs are uniformly and independently distributed strings. The analysis demonstrates that the best possible attack against the HOTP function is the brute force attack. As indicated in the algorithm requirement section, keys SHOULD be chosen at random or using a cryptographically strong pseudorandom generator properly seeded with a random value. Keys SHOULD be of the length of the HMAC output to facilitate interoperability. We RECOMMEND following the recommendations in [RFC4086] for all pseudorandom and random number generations. The pseudorandom numbers used for generating the keys SHOULD successfully pass the randomness test specified in [CN], or a similar well-recognized test. All the communications SHOULD take place over a secure channel, e.g., Secure Socket Layer/Transport Layer Security (SSL/TLS) [RFC5246] or IPsec connections [RFC4301]. We also RECOMMEND storing the keys securely in the validation system, and, more specifically, encrypting them using tamper-resistant hardware encryption and exposing them only when required: for example, the key is decrypted when needed to verify an OTP value, and re-encrypted immediately to limit exposure in the RAM to a short period of time. The key store MUST be in a secure area, to avoid, as much as possible, direct attack on the validation system and secrets database. Particularly, access to the key material should be limited to programs and processes required by the validation system only. M'Raihi, et al. Informational [Page 5]


RFC 6238                      HOTPTimeBased                     May 2011


5.2. Validation and Time-Step Size

An OTP generated within the same time step will be the same. When an OTP is received at a validation system, it doesn't know a client's exact timestamp when an OTP was generated. The validation system may typically use the timestamp when an OTP is received for OTP comparison. Due to network latency, the gap (as measured by T, that is, the number of time steps since T0) between the time that the OTP was generated and the time that the OTP arrives at the receiving system may be large. The receiving time at the validation system and the actual OTP generation may not fall within the same time-step window that produced the same OTP. When an OTP is generated at the end of a time-step window, the receiving time most likely falls into the next time-step window. A validation system SHOULD typically set a policy for an acceptable OTP transmission delay window for validation. The validation system should compare OTPs not only with the receiving timestamp but also the past timestamps that are within the transmission delay. A larger acceptable delay window would expose a larger window for attacks. We RECOMMEND that at most one time step is allowed as the network delay. The time-step size has an impact on both security and usability. A larger time-step size means a larger validity window for an OTP to be accepted by a validation system. There are implications for using a larger time-step size, as follows: First, a larger time-step size exposes a larger window to attack. When an OTP is generated and exposed to a third party before it is consumed, the third party can consume the OTP within the time-step window. We RECOMMEND a default time-step size of 30 seconds. This default value of 30 seconds is selected as a balance between security and usability. Second, the next different OTP must be generated in the next time- step window. A user must wait until the clock moves to the next time-step window from the last submission. The waiting time may not be exactly the length of the time step, depending on when the last OTP was generated. For example, if the last OTP was generated at the halfway point in a time-step window, the waiting time for the next OTP is half the length of the time step. In general, a larger time- step window means a longer waiting time for a user to get the next valid OTP after the last successful OTP validation. A too-large window (for example, 10 minutes) most probably won't be suitable for typical Internet login use cases; a user may not be able to get the next OTP within 10 minutes and therefore will have to re-login to the same site in 10 minutes. M'Raihi, et al. Informational [Page 6]


RFC 6238                      HOTPTimeBased                     May 2011


   Note that a prover may send the same OTP inside a given time-step
   window multiple times to a verifier.  The verifier MUST NOT accept
   the second attempt of the OTP after the successful validation has
   been issued for the first OTP, which ensures one-time only use of an
   OTP.

6. Resynchronization

Because of possible clock drifts between a client and a validation server, we RECOMMEND that the validator be set with a specific limit to the number of time steps a prover can be "out of synch" before being rejected. This limit can be set both forward and backward from the calculated time step on receipt of the OTP value. If the time step is 30 seconds as recommended, and the validator is set to only accept two time steps backward, then the maximum elapsed time drift would be around 89 seconds, i.e., 29 seconds in the calculated time step and 60 seconds for two backward time steps. This would mean the validator could perform a validation against the current time and then two further validations for each backward step (for a total of 3 validations). Upon successful validation, the validation server can record the detected clock drift for the token in terms of the number of time steps. When a new OTP is received after this step, the validator can validate the OTP with the current timestamp adjusted with the recorded number of time-step clock drifts for the token. Also, it is important to note that the longer a prover has not sent an OTP to a validation system, the longer (potentially) the accumulated clock drift between the prover and the verifier. In such cases, the automatic resynchronization described above may not work if the drift exceeds the allowed threshold. Additional authentication measures should be used to safely authenticate the prover and explicitly resynchronize the clock drift between the prover and the validator.

7. Acknowledgements

The authors of this document would like to thank the following people for their contributions and support to make this a better specification: Hannes Tschofenig, Jonathan Tuliani, David Dix, Siddharth Bajaj, Stu Veath, Shuh Chang, Oanh Hoang, John Huang, and Siddhartha Mohapatra. M'Raihi, et al. Informational [Page 7]


RFC 6238                      HOTPTimeBased                     May 2011


8. References

8.1. Normative References

[RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed- Hashing for Message Authentication", RFC 2104, February 1997. [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. [RFC4086] Eastlake 3rd, D., Schiller, J., and S. Crocker, "Randomness Recommendations for Security", BCP 106, RFC 4086, June 2005. [RFC4226] M'Raihi, D., Bellare, M., Hoornaert, F., Naccache, D., and O. Ranen, "HOTP: An HMAC-Based One-Time Password Algorithm", RFC 4226, December 2005. [SHA2] NIST, "FIPS PUB 180-3: Secure Hash Standard (SHS)", October 2008, <http://csrc.nist.gov/publications/fips/ fips180-3/fips180-3_final.pdf>.

8.2. Informative References

[CN] Coron, J. and D. Naccache, "An Accurate Evaluation of Maurer's Universal Test", LNCS 1556, February 1999, <http://www.gemplus.com/smart/rd/publications/pdf/ CN99maur.pdf>. [RFC4301] Kent, S. and K. Seo, "Security Architecture for the Internet Protocol", RFC 4301, December 2005. [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.2", RFC 5246, August 2008. [RFC6030] Hoyer, P., Pei, M., and S. Machani, "Portable Symmetric Key Container (PSKC)", RFC 6030, October 2010. [UT] Wikipedia, "Unix time", February 2011, <http://en.wikipedia.org/wiki/Unix_time>. M'Raihi, et al. Informational [Page 8]


RFC 6238                      HOTPTimeBased                     May 2011


Appendix A. TOTP Algorithm: Reference Implementation

<CODE BEGINS> /** Copyright (c) 2011 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with or without modification, is permitted pursuant to, and subject to the license terms contained in, the Simplified BSD License set forth in Section 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info). */ import java.lang.reflect.UndeclaredThrowableException; import java.security.GeneralSecurityException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.math.BigInteger; import java.util.TimeZone; /** * This is an example implementation of the OATH * TOTP algorithm. * Visit www.openauthentication.org for more information. * * @author Johan Rydell, PortWise, Inc. */ public class TOTP { private TOTP() {} /** * This method uses the JCE to provide the crypto algorithm. * HMAC computes a Hashed Message Authentication Code with the * crypto hash algorithm as a parameter. * * @param crypto: the crypto algorithm (HmacSHA1, HmacSHA256, * HmacSHA512) * @param keyBytes: the bytes to use for the HMAC key * @param text: the message or text to be authenticated */ M'Raihi, et al. Informational [Page 9]


RFC 6238                      HOTPTimeBased                     May 2011


     private static byte[] hmac_sha(String crypto, byte[] keyBytes,
             byte[] text){
         try {
             Mac hmac;
             hmac = Mac.getInstance(crypto);
             SecretKeySpec macKey =
                 new SecretKeySpec(keyBytes, "RAW");
             hmac.init(macKey);
             return hmac.doFinal(text);
         } catch (GeneralSecurityException gse) {
             throw new UndeclaredThrowableException(gse);
         }
     }


     /**
      * This method converts a HEX string to Byte[]
      *
      * @param hex: the HEX string
      *
      * @return: a byte array
      */

     private static byte[] hexStr2Bytes(String hex){
         // Adding one byte to get the right conversion
         // Values starting with "0" can be converted
         byte[] bArray = new BigInteger("10" + hex,16).toByteArray();

         // Copy all the REAL bytes, not the "first"
         byte[] ret = new byte[bArray.length - 1];
         for (int i = 0; i < ret.length; i++)
             ret[i] = bArray[i+1];
         return ret;
     }

     private static final int[] DIGITS_POWER
     // 0 1  2   3    4     5      6       7        8
     = {1,10,100,1000,10000,100000,1000000,10000000,100000000 };













M'Raihi, et al.               Informational                    [Page 10]


RFC 6238                      HOTPTimeBased                     May 2011


     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */

     public static String generateTOTP(String key,
             String time,
             String returnDigits){
         return generateTOTP(key, time, returnDigits, "HmacSHA1");
     }


     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */

     public static String generateTOTP256(String key,
             String time,
             String returnDigits){
         return generateTOTP(key, time, returnDigits, "HmacSHA256");
     }















M'Raihi, et al.               Informational                    [Page 11]


RFC 6238                      HOTPTimeBased                     May 2011


     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */

     public static String generateTOTP512(String key,
             String time,
             String returnDigits){
         return generateTOTP(key, time, returnDigits, "HmacSHA512");
     }


     /**
      * This method generates a TOTP value for the given
      * set of parameters.
      *
      * @param key: the shared secret, HEX encoded
      * @param time: a value that reflects a time
      * @param returnDigits: number of digits to return
      * @param crypto: the crypto function to use
      *
      * @return: a numeric String in base 10 that includes
      *              {@link truncationDigits} digits
      */

     public static String generateTOTP(String key,
             String time,
             String returnDigits,
             String crypto){
         int codeDigits = Integer.decode(returnDigits).intValue();
         String result = null;

         // Using the counter
         // First 8 bytes are for the movingFactor
         // Compliant with base RFC 4226 (HOTP)
         while (time.length() < 16 )
             time = "0" + time;

         // Get the HEX in a Byte[]
         byte[] msg = hexStr2Bytes(time);
         byte[] k = hexStr2Bytes(key);



M'Raihi, et al.               Informational                    [Page 12]


RFC 6238                      HOTPTimeBased                     May 2011


         byte[] hash = hmac_sha(crypto, k, msg);

         // put selected bytes into result int
         int offset = hash[hash.length - 1] & 0xf;

         int binary =
             ((hash[offset] & 0x7f) << 24) |
             ((hash[offset + 1] & 0xff) << 16) |
             ((hash[offset + 2] & 0xff) << 8) |
             (hash[offset + 3] & 0xff);

         int otp = binary % DIGITS_POWER[codeDigits];

         result = Integer.toString(otp);
         while (result.length() < codeDigits) {
             result = "0" + result;
         }
         return result;
     }

     public static void main(String[] args) {
         // Seed for HMAC-SHA1 - 20 bytes
         String seed = "3132333435363738393031323334353637383930";
         // Seed for HMAC-SHA256 - 32 bytes
         String seed32 = "3132333435363738393031323334353637383930" +
         "313233343536373839303132";
         // Seed for HMAC-SHA512 - 64 bytes
         String seed64 = "3132333435363738393031323334353637383930" +
         "3132333435363738393031323334353637383930" +
         "3132333435363738393031323334353637383930" +
         "31323334";
         long T0 = 0;
         long X = 30;
         long testTime[] = {59L, 1111111109L, 1111111111L,
                 1234567890L, 2000000000L, 20000000000L};

         String steps = "0";
         DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         df.setTimeZone(TimeZone.getTimeZone("UTC"));












M'Raihi, et al.               Informational                    [Page 13]


RFC 6238                      HOTPTimeBased                     May 2011


         try {
             System.out.println(
                     "+---------------+-----------------------+" +
             "------------------+--------+--------+");
             System.out.println(
                     "|  Time(sec)    |   Time (UTC format)   " +
             "| Value of T(Hex)  |  TOTP  | Mode   |");
             System.out.println(
                     "+---------------+-----------------------+" +
             "------------------+--------+--------+");

             for (int i=0; i<testTime.length; i++) {
                 long T = (testTime[i] - T0)/X;
                 steps = Long.toHexString(T).toUpperCase();
                 while (steps.length() < 16) steps = "0" + steps;
                 String fmtTime = String.format("%1$-11s", testTime[i]);
                 String utcTime = df.format(new Date(testTime[i]*1000));
                 System.out.print("|  " + fmtTime + "  |  " + utcTime +
                         "  | " + steps + " |");
                 System.out.println(generateTOTP(seed, steps, "8",
                 "HmacSHA1") + "| SHA1   |");
                 System.out.print("|  " + fmtTime + "  |  " + utcTime +
                         "  | " + steps + " |");
                 System.out.println(generateTOTP(seed32, steps, "8",
                 "HmacSHA256") + "| SHA256 |");
                 System.out.print("|  " + fmtTime + "  |  " + utcTime +
                         "  | " + steps + " |");
                 System.out.println(generateTOTP(seed64, steps, "8",
                 "HmacSHA512") + "| SHA512 |");

                 System.out.println(
                         "+---------------+-----------------------+" +
                 "------------------+--------+--------+");
             }
         }catch (final Exception e){
             System.out.println("Error : " + e);
         }
     }
 }

 <CODE ENDS>

Appendix B. Test Vectors

This section provides test values that can be used for the HOTP time- based variant algorithm interoperability test. M'Raihi, et al. Informational [Page 14]


RFC 6238                      HOTPTimeBased                     May 2011


   The test token shared secret uses the ASCII string value
   "12345678901234567890".  With Time Step X = 30, and the Unix epoch as
   the initial value to count time steps, where T0 = 0, the TOTP
   algorithm will display the following values for specified modes and
   timestamps.

  +-------------+--------------+------------------+----------+--------+
  |  Time (sec) |   UTC Time   | Value of T (hex) |   TOTP   |  Mode  |
  +-------------+--------------+------------------+----------+--------+
  |      59     |  1970-01-01  | 0000000000000001 | 94287082 |  SHA1  |
  |             |   00:00:59   |                  |          |        |
  |      59     |  1970-01-01  | 0000000000000001 | 46119246 | SHA256 |
  |             |   00:00:59   |                  |          |        |
  |      59     |  1970-01-01  | 0000000000000001 | 90693936 | SHA512 |
  |             |   00:00:59   |                  |          |        |
  |  1111111109 |  2005-03-18  | 00000000023523EC | 07081804 |  SHA1  |
  |             |   01:58:29   |                  |          |        |
  |  1111111109 |  2005-03-18  | 00000000023523EC | 68084774 | SHA256 |
  |             |   01:58:29   |                  |          |        |
  |  1111111109 |  2005-03-18  | 00000000023523EC | 25091201 | SHA512 |
  |             |   01:58:29   |                  |          |        |
  |  1111111111 |  2005-03-18  | 00000000023523ED | 14050471 |  SHA1  |
  |             |   01:58:31   |                  |          |        |
  |  1111111111 |  2005-03-18  | 00000000023523ED | 67062674 | SHA256 |
  |             |   01:58:31   |                  |          |        |
  |  1111111111 |  2005-03-18  | 00000000023523ED | 99943326 | SHA512 |
  |             |   01:58:31   |                  |          |        |
  |  1234567890 |  2009-02-13  | 000000000273EF07 | 89005924 |  SHA1  |
  |             |   23:31:30   |                  |          |        |
  |  1234567890 |  2009-02-13  | 000000000273EF07 | 91819424 | SHA256 |
  |             |   23:31:30   |                  |          |        |
  |  1234567890 |  2009-02-13  | 000000000273EF07 | 93441116 | SHA512 |
  |             |   23:31:30   |                  |          |        |
  |  2000000000 |  2033-05-18  | 0000000003F940AA | 69279037 |  SHA1  |
  |             |   03:33:20   |                  |          |        |
  |  2000000000 |  2033-05-18  | 0000000003F940AA | 90698825 | SHA256 |
  |             |   03:33:20   |                  |          |        |
  |  2000000000 |  2033-05-18  | 0000000003F940AA | 38618901 | SHA512 |
  |             |   03:33:20   |                  |          |        |
  | 20000000000 |  2603-10-11  | 0000000027BC86AA | 65353130 |  SHA1  |
  |             |   11:33:20   |                  |          |        |
  | 20000000000 |  2603-10-11  | 0000000027BC86AA | 77737706 | SHA256 |
  |             |   11:33:20   |                  |          |        |
  | 20000000000 |  2603-10-11  | 0000000027BC86AA | 47863826 | SHA512 |
  |             |   11:33:20   |                  |          |        |
  +-------------+--------------+------------------+----------+--------+

                            Table 1: TOTP Table



M'Raihi, et al.               Informational                    [Page 15]


RFC 6238                      HOTPTimeBased                     May 2011


Authors' Addresses

   David M'Raihi
   Verisign, Inc.
   685 E. Middlefield Road
   Mountain View, CA  94043
   USA

   EMail: davidietf@gmail.com


   Salah Machani
   Diversinet Corp.
   2225 Sheppard Avenue East, Suite 1801
   Toronto, Ontario  M2J 5C2
   Canada

   EMail: smachani@diversinet.com


   Mingliang Pei
   Symantec
   510 E. Middlefield Road
   Mountain View, CA  94043
   USA

   EMail: Mingliang_Pei@symantec.com


   Johan Rydell
   Portwise, Inc.
   275 Hawthorne Ave., Suite 119
   Palo Alto, CA  94301
   USA

   EMail: johanietf@gmail.com


반응형
728x90


파이썬을 이용한 시스템 트레이딩 (기초편)

https://wikidocs.net/book/110


https://wikidocs.net/1021


파이썬으로 배우는 알고리즘 트레이딩 (네이버 까페)


http://cafe.naver.com/pystock


시스템 트레이딩을 위한 데이터 사이언스 (파이썬 활용편)

https://wikidocs.net/book/486


반응형

'Language > Python' 카테고리의 다른 글

Python에서 데이터 시각화하는 다양한 방법  (0) 2021.10.21
파이썬으로 구글메일 보내기  (0) 2020.12.24

+ Recent posts