NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# C# .NET 매크로 프로그램 만들기. (암호 풀기에 사용할 수 있는 랜덤 텍스트 액션)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 이전 시간에 랜덤 아이디와 랜덤 숫자를 같이 만들어봤는데요. 오늘은 랜덤 텍스트 액션을 만들어 볼께요. 랜덤 텍스트 액션은 주어진 길이만큼 텍스트를 조합해서 문자열을 만드는 기능을 가지고 있습니다. 숫자의 경우에는 단순히 범위에서 하나를 뽑아내기 때문에 코드량이 많지 않았는데요. 랜덤 텍스트는 여러개의 문자를 조합해서 하나의 문자열을 만들어야 하기 때문에 다소 복잡한 부분이 있습니다. 그리고, 조합의 수가 워낙 크기 때문에 배열로 처리하는건 불가능합니다.

     

    이 액션은 랜덤하게 텍스트를 조합해서 어떤 프로그램의 암호를 풀거나 다수의 중복되지 않은 아이디를 만들어서 회원 가입할 때 유용할 수 있습니다. 하지만, 아시다시피 4자리 암호를 푸는 것만해도 마지막까지 모두 돌려면 상당히 많은 시간이 소요될겁니다. 단순히 영어 소문자와 대문자 그리고, 숫자로 이루어진 암호라고 가정 해보겠습니다. 알파벳 숫자는 대소문자 합쳐서 총 52개입니다. 여기에 숫자 10개를 더하면 62개가 되는데요. 그래서, 순열의 경우의 수를 계산해보면 아래와 같습니다.

    hUC3cWt.jpeg

     

    위의 공식을 암호 풀기에 적용하면 13,388,280이 나옵니다. 검증은 엑셀에서 쉽게 할 수 있습니다.

    Pwt12hi.jpeg

     

     

    팩토리얼(!: 계승)로 돌려보면 검산이 가능한데요. 엑셀에서 팩토리얼은 FACT 함수를 사용합니다.
    pLOwsbI.jpeg

     

     

    참고로, 퍼뮤테이션은 순열이고, 콤비네이션은 조합입니다. 아마 맞을거예요. 아무튼, 이렇게 어마무시한 숫자가 나오는데요. 암호를 1초에 한번씩 입력할 수 있다고 가정 해볼께요. 사실, 1초에 한번 입력 한다는건 말이 안되긴 합니다. 못해도 3~5초는 잡아줘야 할거예요. 자~ 그렇다면, 암호를 풀기까지 얼마나 걸리는지 볼까요? 초에서 60으로 두번 나누면 시간을 얻을 수 있습니다. 약 3,718시간이 걸리는군요.

    HdVRZBA.jpeg

     

     

    날짜로 변환해보면 얼마나 걸릴지 예상 해볼 수 있습니다. 24로 나누면 되겠죠? 대략 6개월이 걸린다는걸 알 수 있습니다. 4자리 문자인데도 말이죠. 물론, 숫자로만 입력할 수 있는 4자리라면 훨씬 더 적은 시간에 암호를 풀어낼 수 있을겁니다. 하지만, 숫자로 된 경우는 거의 없기 때문에 4자리의 암호를 푼다고 가정할 때 엄청나게 많은 시간이 소요되는걸 알 수 있습니다. 만약, 특수문자까지 사용한다면... 거의 불가능하다고 생각하시면 됩니다.

    c87jw7J.jpeg

     

     

    만약, 컴퓨터가 100대 있고 암호가 걸린 파일의 암호를 푼다고 생각 해보면, 대략 1시간 50분 정도 걸리는걸 알 수 있습니다.

    Om4BiEy.jpeg
     

     

    그래서, 개인이 암호를 풀기는 어렵지만 엄청나게 많은 컴퓨터 하드웨어를 보유한 대기업의 경우에는 암호를 푸는게 그리 어려운 건 아닙니다. 일단, 다 돌려보면 되니까요. 하지만, 여기에도 맹점은 존재합니다. 파일의 암호 풀기는 문제가 안되지만 몇차례 암호가 틀리면 영원히 잠기는 경우가 있습니다. 3번 틀리면 끝나는거죠. 또는 암호가 틀릴 때마다 10초, 30초, 1분, 1시간... 이렇게 대기 기간이 걸리는 것들도 있습니다. 그래서 암호를 잊으면 안됩니다^^;

     

    만약, 중복되지 않는 어떤 랜덤 텍스트를 이용해서 회원 가입이나 자동으로 아이디를 만들어내야 하는 경우에는 랜덤 텍스트가 꽤 괜찮은 선택일겁니다. 어차피 이미 가입되어 있는 아이디라도 건너뛰면 되니까요. 그리고, 중복되지 않는 조합 또는 순열을 사용한다면 수억개의 아이디를 생성할 수 있을겁니다. 사람이 일일이 하나씩 타이핑 하는 것보다는 효율적입니다. 그리고, 누락시키는 것도 없을거고요.

     

    조합으로 만들어진 텍스트를 받기 위해 결과 속성을 하나 만들어줍니다.

    [LocalizedCategory("Data")]
    [LocalizedDisplayName("Result")]
    [LocalizedDescription("Result")]
    [Browsable(true)]
    [DefaultValue(null)]
    public string? Result { get; set; }

     

    커스텀 옵션들은 사용자가 직접 텍스트 또는 텍스트 배열을 입력할 수 있도록 해줍니다. 예를 들어서 abcdefg... 가 아닌 홍길동, 슈퍼맨, 아이언맨,... 과 같이 어떤 특정 단어들을 쭉~ 적어놓고 여기에서 조합을 만들어 낼 수 있습니다. 그리고, 조합할 때 캐릭터 또는 라인별로 처리할수도 있습니다.

    [LocalizedCategory("Custom")]
    [LocalizedDisplayName("CombinationSourceText")]
    [LocalizedDescription("CombinationSourceText")]
    [DefaultValue(null)]
    [Browsable(true)]
    [EditorAttribute(typeof(MultilineStringEditor), typeof(UITypeEditor))]
    public string? SourceText { get; set; }
    
    [LocalizedCategory("Custom")]
    [LocalizedDisplayName("CombinationSourceTextOption")]
    [LocalizedDescription("CombinationSourceTextOption")]
    [DefaultValue(typeof(Definition.SourceTextOption), "LineSplit")]
    [Browsable(true)]
    public Definition.SourceTextOption SourceTextOption { get; set; } = Definition.SourceTextOption.LineSplit;

     

    사용자가 직접 처리하지 않고, 레터를 이용해서 자동화 하려면 아래와 같은 속성들이 필요합니다. 기본적으로 소문자를 대상으로 조합을 만듭니다. 하지만, 앞서 설명했듯이 소문자뿐만 아니라 대문자 그리고, 숫자와 특수문자까지 조합에 사용할 수 있습니다. 이 속성들은 사용자가 선택하는 옵션들입니다.

    [LocalizedCategory("Action")]
    [LocalizedDisplayName("SmallLetter")]
    [LocalizedDescription("SmallLetter")]
    [DefaultValue(true)]
    [Browsable(true)]
    public bool SmallLetter { get; set; } = true;
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("CapitalLetter")]
    [LocalizedDescription("CapitalLetter")]
    [DefaultValue(false)]
    [Browsable(true)]
    public bool CapitalLetter { get; set; }
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("IncludeNumber")]
    [LocalizedDescription("IncludeNumber")]
    [DefaultValue(false)]
    [Browsable(true)]
    public bool Number { get; set; }
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("SpecialCharacters")]
    [LocalizedDescription("SpecialCharacters")]
    [DefaultValue(false)]
    [Browsable(true)]
    public bool SpecialCharacters { get; set; }

     

    암호 풀기 또는 무한 계정 만들기는 많은 시간이 소요되는 작업입니다. 그렇기 때문에 작업 도중 중간에 멈춰고, 이어서 하고 싶을 수 있습니다. 이런 경우에는 마지막으로 만들어진 조합 문자열을 기록하거나 기억했다가 다음에 다시 실행할 때 시작 문자로 설정해줘야 합니다. 그렇게하면 작업을 이어서 할 수 있습니다.

    [LocalizedCategory("Option")]
    [LocalizedDisplayName("PermutationStartWords")]
    [LocalizedDescription("PermutationStartWords")]
    [DefaultValue(null)]
    [Browsable(true)]
    public string? StartWords { get; set; }

     

    마지막으로 몇개의 문자를 조합할지 선택할 수 있는 Min, Max 속성을 만들어줍니다. 기본적으로 4개를 조합합니다. 하지만, Min을 4로 하고, Max를 8로하면 4개부터 8개까지의 모든 조합을 만들어 냅니다. 거의 무한에 가까운 조합이 만들어질겁니다.

    [LocalizedCategory("Option")]
    [LocalizedDisplayName("CombinationMinLength")]
    [LocalizedDescription("CombinationMinLength")]
    [DefaultValue(4)]
    [Browsable(true)]
    public int Minimum { get; set; } = 4;
    
    [LocalizedCategory("Option")]
    [LocalizedDisplayName("CombinationMaxLength")]
    [LocalizedDescription("CombinationMaxLength")]
    [DefaultValue(4)]
    [Browsable(true)]
    public int Maximum { get; set; } = 4;

     

    조합에 필요한 함수를 먼저 만들어 줄께요.

    public string? VariationGenerate(IPlayer player, string allowed, int minimum, int maximum, bool useRepeatedPermutation)
    {
        string? result = null;
    
        if (player.Variations == null)
        {
            player.Variations = new Ai.Api.Combination.Variations<char>(
                allowed.ToArray(),
                minimum + player.VariationMinLength,
                useRepeatedPermutation ? Definition.GenerateOption.WithRepetition : Definition.GenerateOption.WithoutRepetition);
            player.VariationEnumerator = player.Variations.GetEnumerator();
        }
    
        if (player.VariationEnumerator.MoveNext())
            result = string.Join(string.Empty, player.VariationEnumerator.Current);
        else
            player.VariationMinLength++;
    
        return result;
    }

     

    조건에 따라서 처리하는 로직을 만들어줍니다. 소문자, 대문자, 숫자, 특수문자 선택에 따라서 allowed 캐릭터 배열을 만듭니다. 그리고, switch 옵션에 따라서 순열 또는 조합을 처리해줍니다. 참고로, 중복 없는 순열 또는 조합을 만들기 위해서는 정보를 기록해놔야 하는데요. 이 기록 장치는 플레이어가 담당합니다. 다수의 물리적인 장치에서 매크로를 돌릴 수 있으면 처리 결과를 담는 데이터를 플레이어가 아닌 매니저로 승격 시켜야 할거 같기도 한데요. 이 부분은 나중에 처리하기로 하고, 일단은 로컬 영역에 가둬두고 테스트를 해볼께요.

    string allowed = string.Empty;
    
    if (SmallLetter)
        allowed += Definition.SmallLetter;
    
    if (CapitalLetter)
        allowed += Definition.CapitalLetter;
    
    if (Number)
        allowed += Definition.Number;
    
    if (SpecialCharacters)
        allowed += Definition.SpecialCharacters;
    
    if (string.IsNullOrEmpty(allowed))
    {
        player.Manager.Output.WriteLine(player.Manager.Client.ResxMessage.GetString("NotAllowed"), log4net.Core.Level.Warn);
        return null;
    }
    
    switch (Option)
    {
        case Definition.RandomTextOption.Random:
            Result = Ai.Api.Combination.Manager.RandomTextGenerator(allowed, Minimum, Maximum + 1);
            break;
        case Definition.RandomTextOption.Permutation:
            if (player.PermutationStartWordsCheck || string.IsNullOrEmpty(StartWords))
                Result = VariationGenerate(player, allowed, Minimum, Maximum + 1, UseRepeatedPermutation);
            else
            {
                while (true)
                {
                    Result = VariationGenerate(player, allowed, Minimum, Maximum + 1, UseRepeatedPermutation);
    
                    if (Result == StartWords)
                    {
                        Result = VariationGenerate(player, allowed, Minimum, Maximum + 1, UseRepeatedPermutation);
                        player.PermutationStartWordsCheck = true;
                        break;
                    }
                }
            }
            break;
        case Definition.RandomTextOption.RandomPermutation:
            allowed = string.Join(string.Empty, allowed.ToArray().OrderBy(o => random.Next()));
            Result = VariationGenerate(player, allowed, Minimum, Maximum + 1, UseRepeatedPermutation);
            break;
    }

     

    이제 정상적으로 동작하는지 알아보기 위해 테스트용 예제를 하나 만들었습니다. Microsoft의 Access 데이터베이스는 파일에 암호를 걸 수 있습니다. 아래 그림처럼요.

    OscdCi9.jpeg

     

     

    이걸 이용해서 테스트를 진행 해보면 될거 같습니다.

     

     

    이 글이 도움이 되셨다면~ 커피 한잔이라도 후원 부탁드립니다^^

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.