말 그대로 글자 하나하나를 다른 알파벳으로 대치해서 암호화하는 것.
예전에 한글을 만들어서 사용해 봤으나 1시간만에 친구에게 해독되었다.......

전수 조사 공격에는 비교적 강인한 특성을 가지지만 이렇게 출현 빈도수를 따라 통계학 적인 방법으로 분석하면 비밀 키를 찾아내는 것이 어렵지만은 않다. 

'정보 보안' 카테고리의 다른 글

전치암호(transposition chipher)  (0) 2011.05.21
Vigenere 암호(Vigenere cipher)  (0) 2011.05.21
시저 암호(Caesar cipher)  (0) 2011.05.21
 가장 오래된 암호중 하나.
 줄리어스 시저(Julius Caesar)가 사용하여 그 이름이 유래.
 
 가장 대표적인 대치 암호(substitution cipher)

평문 문자를 다르 문자로 일대일 대응시켜 암호문을 만들어 내는 방식.

 
 a  0  n  13
 b  1  o  14
 c  2  p  15
 d  3 q  16
 e  4  r  17
 f  5  s  18
 g  6  t  19
 h  7  u  20
 i  8  v  21
 j  9  w 22 
 k  10  x  23
 l  11  y  24
 m 12   z  25

 영문 문자에 번호를 0부터 25까지 부여하여 이 문자를 비밀키와 조합하여 법연산하는 것이 특징.

만약 암호용 비밀키가 k라고 가정하고 평문은 p 암호문이 c라고 하면

c = p+k mod 26
m = c - k mod 26

이 되는 것이다.

여기서 시저 암호의 키는 평문의 시프트 간격인 k 가 되고 mod 26이란 모듈러 연산으로 합의 값을 다시 26으로 나눈 나머지 값을 의미한다.

ex

평문 :: My name is Peace
비밀 키 :: 6
암호문 ::  Se tgsk oy Vkgik
복호 키 ::-6
복호 문 :: My name is Peace

C++로 만들어진 코드


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
#include <iostream>
#include <cstring>
 
using namespace std;
 
int main()
{
    int i=0, key=0, str_size=0;
    char str[50={0,};
 
    cout<<"평문 또는 암호문을 입력하시오 "<<endl;
    gets(str); // Enter가 들어올때까지 입력을 받기위해 gets를 사용했다.    
 
    cout<<"키 값을 입력하세요 : ";
    cin>>key;    
 
    str_size=strlen(str); // 평문, 암호문의 길이를 구한다.    
 
    for(i=0;i<str_size;i++)
    {
        if((str[i]>='a')&&(str[i]<='z'))
        {
            str[i]-='a';
 
            if((str[i]+key) <0)
                str[i]+=26;            
 
            str[i] =(str[i]+key)%26;
            str[i]+='a';
        }        
 
        if((str[i] >='A')&&(str[i]<='Z'))
        {
            str[i]-='A';
 
            if((str[i]+key)<0)
                str[i]+=26;            
 
            str[i]=(str[i]+key)%26;
            str[i]+='A';
        }
    }    
 
    cout<<endl<<"암호화 또는 복호화된 결과 출력 : "<<str<<endl;
 
    return 0;
 
 
 
cs





C++에서 복사생성자를 사용할때 주의 사항
 * 묵시적 변환
 만약,
class example{
private:
public:
  example(){}
};
void main()
{
  example a;
  example b=a;
}

라는 코드가 있을 때
example b=a;
라는 코드는
묵시적으로 example b(a);
라는 코드로 묵시적으로 변환.

(참고 이를 막기 위해 explicit라는 키워드가 존재. 묵시적 변환을 막으려면, 복사 생성자 함수 앞에 explicit를 넣어주면, 묵시적으로 변환하지 않음.)

=> 형식

class example{
private:
public:
  example(){}
  example(const example &a){}
};

요롷게 선언을 해주면 됨.
함수 오버로딩에 따라 클래스를 복사할경우, 클래스 하나를 다시 생성해줌.

'Programming > C/C++' 카테고리의 다른 글

무식하게 소수 판별 하는 방법  (0) 2013.07.29
 ARM의 데이터 이동명령어는 크게 3가지로 나눌 수 있습니다.
  • 한 레지스터를 이동시키는 명령어
  • 여러개의 레지스터를 이동시키는 명령어
  • Swap 명령어

 첫번재의 move single register instruction이 가장 일반적입니다. 그리고 그렇게 크게 어려운 점은 없다고 봐도 될 것입니다. 그리고 세번째로 나와 있는 스왑(SWAP)명령어는 사용자로서는 잘 사용하지 않고 다중프로세서 시스템에서 공유 데이터 관리를 위해 주로 사용됩니다.
 하지만 이 챕터. 아니 명령어를 이해하는데 가장 걸림 돌이 되는 것은 무슨 프로그래밍이든 구조든지 메모리 access가 아닐까 생각됩니다. 특히 두번째에 언급했던 mutiple register road and store는 많은 데이터를 블럭단위(연속된 메모리주소)로 이동하는데 적합하고 ARM을 더욱 효율적으로 만들었습니다.
 이 Multiple Register Road and Store를 조금 더 부연설명을 하자면 최대 16개(레지스터의 가용갯수)까지 가능합니다.

 ARM에서의 이동명령어는 모두 레지스터를 이용한 간접 주소지정모드를 사용하게 된다. 레지스터 간접주소지정 방법은 한 레지스터에 메모리 주소값을 넣어두고 그 값을 주소로 이용하여 메모리에서 데이터를 읽어서 오퍼랜드를 가져오거나 메모리에 데이터를 써서 오퍼랜드를 저장합니다. 이때 메모리 주소값이 들어가 있던 레지스터를 베이스 레지스터(Base Register)라고 합니다.

 일단 ARM에서 유일안 메모리 접근 명령어인 LDR와 STR 명령어의 예를 살펴보도록 하겠습니다.

 LDR r1,[r2] ; r1 <- memory[r2]

 이 위의 예제는 r1에 다가 저장을 하는데 r2에 있는 값이 아니라 현재 r2에는 메모리의 주소값이 저장되어 있을 겁니다. 그 주소값이 가르키는 값을 r1에다가 저장하라는 것입니다. C 언어로 이야기 하자면 포인터 정도가 될 것 같습니다. 아, 그리고 STR도 한번 살펴보고 가도록 하겠습니다.

STR r1,[r2] ; memory[r2] <- r1

 이 위의 예제는 메모리에 값을 저장하는 예 입니다. LDR의 예제와 마찬가지로 r2가 가르키는 곳에 r1값을 저장하고 있습니다.  여기서 중요한 것은 데이터의 이동방향입니다. 이것을 헤깔리지 않도록 하는것이 중요합니다.

 
 이번에는 그렇다면 위의 예제에서 어떻게 r2에 memory 주소를 넣을 수 있을지 생각해보도록 하겠습니다. 첫번째로는 프로그램의 시작위치에서 계산하는 방법이있습니다. 이것이 가능한 이유는 r15가 pc, 즉 프로그램이 시작되는 부분을 가르키기 때문에 여기서 뺄셈을 해서 사용하면 됩니다.
 하지만 이 방법은 번거롭기도 하고 사용자가 하기에는 자칫잘못했다가는 엉키는 작업입니다. 그래서 생긴 명령어가 ADR 명령어 입니다.
 원래 명령어라는 것은 CPU가 처리하는 것 입니다. 하지만 이 ADR 이라는 명령어는 CPU에 명령하는 것이 아닙니다. 바로 컴파일러에게 알려주는 것입니다. 그래서 이 ADR명령어를 슈도(pseudo)명령어, 즉 가상명령어라고 합니다. 이 ADR 명령어 사용방법을 알아보기 위해 예제를 하나 제시하겠습니다.
 
ADR r1, TABLE1 ;

 r1에 TABLE1의 주소값을 대입합니다. 사용자는 TABLE1의 주소값을 모릅니다. 하지만 ARM은 알고 있습니다. 사실 사용자는 알 필요가 없습니다. 굳이 알고 싶다면 r1을 출력하면 되지만 컴퓨터가 알아서 해주는데 굳이 TABLE1의 주소를 알 필요는 없습니다. 이렇게 사용자가 사용가능한 메모리의 주소값을 얻었습니다.

 
그럼 이제는 이 r1의 다음 주소를 알아내는 방법입니다. 이것을 base plus offset 주소지정이라고 합니다.
 다음 중 r2에 r1의 다음주소에 있는 값을  저장 하는 코드는 무엇일까요? 

  1. LDR r2,[r1,#1]
  2. LDR r2,[r1,#4]
  3. LDR r2,[r1,#16]
  4. LDR r2,[r1,#32]

일단 생각을 해보도록하자. r1의 주소가 만약 0x1000 이라고 한다면 r1,#1은 0x1001이 될것입니다. 오, 이거 그럴사 합니다. 하지만 ARM에서 사용하는 값들은 32bit의 길이로 저장됩니다. 오! 그렇다면 정답은 4번 r1,#32 가 되어 0x1032? 땡! 아닙니다. 왜냐하면 일반적으로 주소값을 사용할때는 bit단위가 아닌 byte단위를 사용하게 때문에 답은 2번 r1,#4 즉 0x1000 번지의 다음번지는 0x1004가 됩니다.

 이렇게 base plus offset주소를 지정하는데 3가지 방법이 있습니. 지금 방금 사용한 방법이 pre-indexing이라고 합니다.

 pre-indexing이란 명령어를 실행하기 전에 base 에다가 Offset을 더해 주소에 있는 값을 레지스터에 더하는 것입니다.
 그다음은 Post-indexing 입니다. post-indexing이란 pre-indexing의 반대 개념으로 base 값만으로 명령어 실행후 base 값에 offset을 더해 base에 저장합니다. 그리고는 다음 실행시 반영합니다. 즉 저장후 base 값을 update 시키는 것 입니다. 예를 들어 보겠습니다.

 LDR r0,[r1],#4 ;
 
 이렇게 하면 r0에 r1의 값을 저장 한 후 r1의 값을 그 다음주소값으로 update 시켜 줍니다. 그래서 다음 실행시 반영이 됩니다. 

 그리고 마지막으로 auto-indexing이 있습니다. auto-indexing은 두개를 합쳐놓은 것인데 일단 pre-indexing으로 계산을 한 후에 base register를 update 합니다. 다시 정리 해 보자면

pre-indexing은 update하여 주소에 있는 값을 register에 저장하고
post-indexing은 주소에 있는 값은 register에 저장 한 후 base값을 update 합니다.
auto-indexing은 update하여 주소에 있는 값을 register에 저장하고 또 base 값을 update하게 됩니다.

이 auto-indexing을 사용하는 방법은 pre-indexing의 명령어 뒤에 '!'를 넣어주면 됩니다.

 LDR r2,[r1,#4]! ;



 


  


'ARM(Advanced RISC Machine)' 카테고리의 다른 글

2.1 ARM 데이터 처리 명령어  (0) 2009.10.23
2 - ARM과 Assembly  (0) 2009.10.23
1.4 - ARM의 Instructions  (0) 2009.10.23
1.3 - ARM의 Register  (0) 2009.10.23
1.2 - ARM과 Bekeley RISC  (0) 2009.10.23
 이번 절에서는 ARM 명령어중 데이터 처리 명령어를 알아보겠습니다.
 일단 ARM 데이터 처리 명령어에는 크게 1. 레지스터 오퍼랜드 명령어와 2.시프트(shift)된 레지스터 operand가 있습니다.
 또 레즈스터 오퍼랜드 명령어에는 
  • 산술 명령어
  • 비트논리연산 명령어
  • 레지스터이동 명령어
  • 비교명령어

가 있습니다.
 
 일단 산술명령어는 2진 덧셈, 뺄셈을 뜻합니다. 이때 오퍼랜드는 32bit를 사용하고 부호를 사용하지 않을수도 있고 부호를 사용한다면 2의 보수체계를 사용합니다.
 ADD : 덧셈, ADC : carry와 함께 덧셈
 SUB : 뺄셈 SBC : 케리와 함께 뺄샘
 RSB : 역순으로 뺄셈 RSC : 역순으로 케리와 함께 뺄셈

 비트논리 연산명령어는 두개의 오퍼랜드의 비트를 연산하는 명령어입니다. 예를 들어 11 곱하기 23을 일반적으로 하면 230+23이 되어 253입니다. 하지만 비트연산을 하면 11을 2진수로 표현하면
 01101(2), 23은 10111(2) 입니다. 이 둘을 AND 비트연산을 하면 00101(2)이 되어 5가 됩니다.

레지스터 이동 명령어는 두번재 오퍼랜드첫번재 오퍼랜드로 이동시키는 명령어 입니다. 예를 들어 
 MOV R0,R2 ; r0 := r2 
가 됩니다. 
 하지만 이 과정을 조금 더 정확히 보자고 한다면 이것은 연산명령어, 즉 ALU를 거쳐가야 하므로 사실은 R2에 0을 더하는 연산명령어 입니다.다시 말하면 MOV R0,R2 는 ADD R0,R2,#0 을 바꿔서 쓴 것이라고 생각해도 무방합니다.

 비교명령어는 연산을 하지만 결과값을 레지스터에 저장하는 것이 아니라 CPSR의 Condition flag만이 update된다.

 여기서 ARM CPU만의 특징이 하나 더 나오는데 그것은 바로 Default flag update가 안된다는 점이다. 보통 cpu들은 이런 연산을 할 경우 명령어에 특별한 명령을 더 하지 않아도 flag가 update된다 하지만 ARM CPU에서는 ADD를 하더라도 ADDEQ 와 같은 뒤에 명령어를 더 붙여줘야만 flag가 업데이트 된다.
 
 
이번에는 시프트된 오퍼랜드에 대해 살펴 보겠다.

이 ARM 명령어 세트 형식을 보면 두번재 소스의 코드 길이가 12bit나 된다. 왜 이렇게 많은 bit를 할당해놨을까? 그 이유는 ALU의 shifter에 있다.
 ARM의 ALU의 두번째 source operand쪽 회로에는 Shifter가 달려있다. 즉, 모든 2nd source가 ALU연산을 할 때 shifter를 거친다는 말이다. 이런 이유로 RSB같은 명령어가 존재한다.(뒤에 있는 오퍼랜드를 shift 연산하여 뺄 경우)
 사용 예는 이렇다.
 ADD r0,r1,r2,LSL #3 ; r0 = r1 + (r2 * 3)
이 shift는 한 사이클에 모두 해결되며 31bit까지 할 수 있다. 물론 이 shift의 방법에도 여러가지가 있다.
 

  • LSL : 왼쪽으로 쉬프트 후 LSB(1의 자리)의 빈자리를 0으로 채움
  • LSR : 오른쪽으로 쉬프트 후 MSB(부호비트)의 빈자리를 0으로 채움
  • ASL : LSL과 같음
  • ASR : 오른쪽으로 쉬프트 한 후 MSB(부호비트)의 빈자리가 양수인 경우에는 0 음수인 경우에는 1로 채운다.
  • ROR : 오른쪽으로 쉬프트 한 후 LSB에서 밖으로 나온 비트는 다시 MSB로 들어간다
  • RRX  : MSB가 비워지면 CCR의 C flag가 입력된다. 나머지는 ROR과 같음


또한 알아두어야 할 것은 Condition Code의 설정이다. 일반적으로 TST 또는 CMP와 같은 비교명령들을 제외한 일반 산술 및 논리 연산은 ARM CPU의 특성에 따라 Condition flag를 update시키지 못한다. 따라서 condition flag를 update시키려면 명령어 끝에 'S'를 붙여 주어야만한다.

'ARM(Advanced RISC Machine)' 카테고리의 다른 글

2.2 - ARM 데이터 이동 명령어 -1  (0) 2009.10.23
2 - ARM과 Assembly  (0) 2009.10.23
1.4 - ARM의 Instructions  (0) 2009.10.23
1.3 - ARM의 Register  (0) 2009.10.23
1.2 - ARM과 Bekeley RISC  (0) 2009.10.23

+ Recent posts